﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Reflection;
using Microsoft.Win32.SafeHandles;
using Go;

namespace GoRpc
{
    static public class Rpc
    {
        public enum ExitCode
        {
            Undefined,
            LocalClose,
            RemoteClose,
            SessionClose,
            SocketClosed,
            KeepOvertime,
            RecvKeepOvertime,
            RecvBinOvertime,
            RecvBinError,
            SendBinOvertime,
            DataHeadError,
            ReplySerializeError,
            RequestSerializeError,
            ReplyDeserializeError,
            RequestDeserializeError,
        }

        [Serializable]
        public enum ReplyState
        {
            Fail,
            IsNull,
            Success,
            Stopped,
            NotFound,
            Overtime,
            Exception,
            IndexError,
            LocalCancel,
            RemoteCancel,
            ArgsTypeError,
            ArgsCountError,
            ResultTypeError,
            LocalSerializeError,
            RemoteSerializeError,
            LocalDeserializeError,
            RemoteDeserializeError,
        }

        class CastArgsException : Exception
        {
            public ReplyState state = ReplyState.ArgsTypeError;
        }

        const BindingFlags InstanceFlag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

        abstract public class ParamTuple
        {
            [Serializable]
            internal struct SerializePack
            {
                public string name;
                public object value;
            }

            [Serializable]
            internal struct Serialize
            {
                public bool tupleWrap;
                public string name;
                public SerializePack[] array;
            }

            [AttributeUsage(AttributeTargets.Field)]
            public class Name : Attribute
            {
                internal string rename;

                public Name(string rename)
                {
                    this.rename = rename;
                }
            }

            [AttributeUsage(AttributeTargets.Class)]
            public class Match : Attribute
            {
                internal string rename;

                public Match(string rename)
                {
                    this.rename = rename;
                }
            }

            internal abstract class TupleWrap : ParamTuple
            {
                abstract public object array { get; }
            }

            internal class TupleArray<T> : TupleWrap
            {
                T _obj;

                public TupleArray()
                {
                }

                public TupleArray(T array)
                {
                    _obj = array;
                }

                public TupleArray(object array)
                {
                    _obj = (T)array;
                }

                override public object array
                {
                    get
                    {
                        return _obj;
                    }
                }
            }

            internal class TypeInfo
            {
                public string name;
                public bool[] isParam;
                public Type[] fieldTypes;
                public string[] paramNames;
                public Func<ParamTuple> newTuple;
                public Func<object, object>[] getValue;
                public Action<object, object>[] setValue;
            }

            protected ParamTuple() { }

            protected ParamTuple(object objects)
            {
                if (objects is Serialize)
                {
                    Objects = (Serialize)objects;
                }
                else
                {
                    throw new CastArgsException();
                }
            }
#if DEBUG
            static bool CheckTempType(Type[] types)
            {
                for (int i = 0; i < types.Length; i++)
                {
                    if (types[i].IsSubclassOf(typeof(ParamTuple)))
                    {
                        return false;
                    }
                    if (!CheckTempType(types[i].GetGenericArguments()))
                    {
                        return false;
                    }
                }
                return true;
            }

            static public void AssertName()
            {
                Dictionary<string, void_type> nameDict = new Dictionary<string, void_type>();
                Assembly assembly = Assembly.GetCallingAssembly();
                Type[] allTypes = assembly.GetTypes();
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    bool isMatch = Attribute.IsDefined(type, typeof(Match), false);
                    if (!type.IsSubclassOf(typeof(ParamTuple)) && !isMatch)
                    {
                        continue;
                    }
                    TypeInfo typeInfo = GetTypeInfo(type);
                    if (!isMatch)
                    {
                        continue;
                    }
                    assert.check(Methods.CheckName(typeInfo.name), $"Rpc.ParamTuple 命名错误 {typeInfo.name}\r\n\r\n{assembly.FullName}");
                    if (nameDict.ContainsKey(typeInfo.name))
                    {
                        assert.check(false, $"Rpc.ParamTuple 定义名称 {typeInfo.name} 重复\r\n\r\n{assembly.FullName}");
                    }
                    else
                    {
                        nameDict.Add(typeInfo.name, default);
                    }
                }
                foreach (var type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    if (!Attribute.IsDefined(type, typeof(Match), false))
                    {
                        continue;
                    }
                    nameDict.Clear();
                    TypeInfo typeInfo = GetTypeInfo(type);
                    if (!type.IsSubclassOf(typeof(ParamTuple)))
                    {
                        assert.check(false, $"{typeInfo.name} 没有继承自 Rpc.ParamTuple\r\n\r\n{assembly.FullName}");
                    }
                    foreach (string name in typeInfo.paramNames)
                    {
                        assert.check(Methods.CheckName(name), $"{typeInfo.name} 命名错误 {name}\r\n\r\n{assembly.FullName}");
                        if (nameDict.ContainsKey(name))
                        {
                            assert.check(false, $"{typeInfo.name} 字段名称 {name} 重复\r\n\r\n{assembly.FullName}");
                        }
                        else
                        {
                            nameDict.Add(name, default);
                        }
                    }
                }
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    if (!type.IsSubclassOf(typeof(ParamTuple)))
                    {
                        continue;
                    }
                    TypeInfo typeInfo = GetTypeInfo(type);
                    if (null == typeInfo.name)
                    {
                        FieldInfo[] fields = type.GetFields(InstanceFlag);
                        for (int i = 0; i < typeInfo.fieldTypes.Length; i++)
                        {
                            assert.check(CheckTempType(fields[i].FieldType.GetGenericArguments()), $"{type.Name} 字段 {fields[i].Name} 的模板不能使用ParamTuple派生类型\r\n\r\n{assembly.FullName}");
                        }
                    }
                    else
                    {
                        for (int i = 0; i < typeInfo.fieldTypes.Length; i++)
                        {
                            assert.check(CheckTempType(typeInfo.fieldTypes[i].GetGenericArguments()), $"{typeInfo.name} 字段 {typeInfo.paramNames[i]} 的模板不能使用ParamTuple派生类型\r\n\r\n{assembly.FullName}");
                        }
                    }
                }
            }
#else
            static public void AssertName()
            {
                Assembly assembly = Assembly.GetCallingAssembly();
                Type[] allTypes = assembly.GetTypes();
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    if (!type.IsSubclassOf(typeof(ParamTuple)))
                    {
                        continue;
                    }
                    GetTypeInfo(type);
                }
            }
#endif
            static internal bool IsParamTuple(Type type)
            {
                while (type.IsArray)
                {
                    type = type.GetElementType();
                }
                return type.IsSubclassOf(typeof(ParamTuple));
            }

            static ConcurrentDictionary<Type, Func<object, TupleWrap>> tupleWraps = new ConcurrentDictionary<Type, Func<object, TupleWrap>>();
            static internal object SerializeCheck(object obj)
            {
                if (!(obj is Array))
                {
                    if (!(obj is ParamTuple))
                    {
                        return obj;
                    }
                    return ((ParamTuple)obj).Objects;
                }
                Type type = obj.GetType();
                if (!tupleWraps.TryGetValue(type, out var newTuple))
                {
                    if (IsParamTuple(type.GetElementType()))
                    {
                        newTuple = CreateNew<Func<object, TupleWrap>>(typeof(TupleArray<>).MakeGenericType(type));
                    }
                    tupleWraps.TryAdd(type, newTuple);
                }
                if (null == newTuple)
                {
                    return obj;
                }
                Serialize result = newTuple(obj).Objects;
                result.tupleWrap = true;
                return result;
            }

            static internal R DeserializeCheck<R>(object obj)
            {
                if (!(obj is Serialize))
                {
                    return (R)obj;
                }
                Serialize serialize = (Serialize)obj;
                if (!serialize.tupleWrap)
                {
                    return (R)(object)GetTypeInfo(typeof(R)).newTuple().SetObjects(serialize);
                }
                Type type = typeof(R);
                if (!tupleWraps.TryGetValue(type, out var newTuple))
                {
                    if (IsParamTuple(type))
                    {
                        newTuple = CreateNew<Func<object, TupleWrap>>(typeof(TupleArray<>).MakeGenericType(type));
                    }
                    tupleWraps.TryAdd(type, newTuple);
                }
                if (null == newTuple)
                {
                    return (R)obj;
                }
                return (R)((TupleWrap)newTuple(null).SetObjects(serialize)).array;
            }

            static object GetParams(Type type, object value)
            {
                if (null == value)
                {
                    return null;
                }
                if (!type.IsArray)
                {
                    return ((ParamTuple)value).Objects;
                }
                Type elementType = type.GetElementType();
                Array array = (Array)value;
                int rank = array.Rank;
                if (1 == rank)
                {
                    object[] values = (object[])value;
                    object[] objects = new object[values.Length];
                    for (int i = 0; i < values.Length; i++)
                    {
                        objects[i] = GetParams(elementType, values[i]);
                    }
                    return objects;
                }
                else
                {
                    int[] shape = new int[rank];
                    int number = 1;
                    for (int i = 0; i < rank; i++)
                    {
                        shape[i] = array.GetLength(i);
                        number *= shape[i];
                    }
                    Array objects = Array.CreateInstance(typeof(object), shape);
                    int[] indices = new int[rank];
                    while (0 != number--)
                    {
                        objects.SetValue(GetParams(elementType, array.GetValue(indices)), indices);
                        for (int i = rank - 1; i >= 0; i--)
                        {
                            int c = indices[i] + 1;
                            if (c < shape[i])
                            {
                                indices[i] = c;
                                break;
                            }
                            indices[i] = 0;
                        }
                    }
                    return objects;
                }
            }

            static object SetParams(Type type, object oldObj, object value)
            {
                if (null == value)
                {
                    return null;
                }
                if (!type.IsArray)
                {
                    return ((ParamTuple)(oldObj ?? GetTypeInfo(type).newTuple())).SetObjects(value);
                }
                Type elementType = type.GetElementType();
                Array array = (Array)value;
                int rank = array.Rank;
                if (1 == rank)
                {
                    object[] values = (object[])value;
                    object[] objects;
                    if (null == oldObj)
                    {
                        objects = (object[])Activator.CreateInstance(type, values.Length);
                    }
                    else
                    {
                        object[] oldObjs = (object[])oldObj;
                        if (oldObjs.Length == values.Length)
                        {
                            objects = oldObjs;
                        }
                        else
                        {
                            objects = (object[])Activator.CreateInstance(type, values.Length);
                            for (int i = 0; i < oldObjs.Length && i < objects.Length; i++)
                            {
                                objects[i] = oldObjs[i];
                            }
                        }
                    }
                    for (int i = 0; i < values.Length; i++)
                    {
                        objects[i] = SetParams(elementType, objects[i], values[i]);
                    }
                    return objects;
                }
                else
                {
                    int[] shape = new int[rank];
                    int number = 1;
                    for (int i = 0; i < rank; i++)
                    {
                        shape[i] = array.GetLength(i);
                        number *= shape[i];
                    }
                    Array objects;
                    if (null == oldObj)
                    {
                        objects = Array.CreateInstance(elementType, shape);
                    }
                    else
                    {
                        objects = (Array)oldObj;
                        if (objects.Rank != array.Rank)
                        {
                            return null;
                        }
                        for (int i = 0; i < rank; i++)
                        {
                            if (shape[i] != objects.GetLength(i))
                            {
                                objects = Array.CreateInstance(elementType, shape);
                                break;
                            }
                        }
                    }
                    int[] indices = new int[rank];
                    while (0 != number--)
                    {
                        objects.SetValue(SetParams(elementType, objects.GetValue(indices), array.GetValue(indices)), indices);
                        for (int i = rank - 1; i >= 0; i--)
                        {
                            int c = indices[i] + 1;
                            if (c < shape[i])
                            {
                                indices[i] = c;
                                break;
                            }
                            indices[i] = 0;
                        }
                    }
                    return objects;
                }
            }

            static readonly ConcurrentDictionary<Type, TypeInfo> typeInfos = new ConcurrentDictionary<Type, TypeInfo>();
            static internal TypeInfo GetTypeInfo(Type type)
            {
                if (!typeInfos.TryGetValue(type, out TypeInfo typeInfo))
                {
                    if (!type.IsSubclassOf(typeof(ParamTuple)))
                    {
                        assert.check(false, $"{type.Name} 不是继承自 Rpc.ParamTuple");
                    }
                    FieldInfo[] fields = type.GetFields(InstanceFlag);
                    Match dict = (Match)Attribute.GetCustomAttribute(type, typeof(Match), false);
                    typeInfo = new TypeInfo();
                    typeInfo.name = dict?.rename;
                    typeInfo.newTuple = CreateNew<Func<ParamTuple>>(type);
                    typeInfo.isParam = new bool[fields.Length];
                    typeInfo.fieldTypes = new Type[fields.Length];
                    typeInfo.paramNames = new string[fields.Length];
                    typeInfo.getValue = new Func<object, object>[fields.Length];
                    typeInfo.setValue = new Action<object, object>[fields.Length];
                    for (int i = 0; i < fields.Length; i++)
                    {
                        typeInfo.paramNames[i] = ((Name)Attribute.GetCustomAttribute(fields[i], typeof(Name), false))?.rename;
                        typeInfo.getValue[i] = CreateObjectGetter(fields[i]);
                        typeInfo.setValue[i] = CreateObjectSetter(fields[i], false);
                        typeInfo.isParam[i] = IsParamTuple(fields[i].FieldType);
                        typeInfo.fieldTypes[i] = fields[i].FieldType;
                    }
                    typeInfos.TryAdd(type, typeInfo);
                }
                return typeInfo;
            }

            internal Serialize Objects
            {
                get
                {
                    TypeInfo typeInfo = GetTypeInfo(GetType());
                    SerializePack[] array = new SerializePack[typeInfo.getValue.Length];
                    for (int i = 0; i < typeInfo.getValue.Length; i++)
                    {
                        array[i].name = typeInfo.paramNames[i];
                        if (typeInfo.isParam[i])
                        {
                            array[i].value = GetParams(typeInfo.fieldTypes[i], typeInfo.getValue[i](this));
                        }
                        else
                        {
                            array[i].value = typeInfo.getValue[i](this);
                        }
                    }
                    return new Serialize { name = typeInfo.name, array = array };
                }
                set
                {
                    if (null == value.array)
                    {
                        throw new CastArgsException();
                    }
                    TypeInfo typeInfo = GetTypeInfo(GetType());
                    if (null == typeInfo.name)
                    {
                        if (typeInfo.setValue.Length != value.array.Length)
                        {
                            throw new CastArgsException();
                        }
                        for (int i = 0; i < typeInfo.setValue.Length; i++)
                        {
                            try
                            {
                                if (typeInfo.isParam[i])
                                {
                                    typeInfo.setValue[i](this, SetParams(typeInfo.fieldTypes[i], typeInfo.getValue[i](this), value.array[i].value));
                                }
                                else
                                {
                                    typeInfo.setValue[i](this, value.array[i].value);
                                }
                            }
                            catch (Exception)
                            {
                                throw new CastArgsException();
                            }
                        }
                    }
                    else if (typeInfo.name == value.name)
                    {
                        int lastOffset = 0;
                        for (int i = 0; i < typeInfo.setValue.Length; i++)
                        {
                            try
                            {
                                for (int j = 0; j < value.array.Length; j++)
                                {
                                    int k = lastOffset + j;
                                    if (k >= value.array.Length)
                                    {
                                        k -= value.array.Length;
                                    }
                                    if (typeInfo.paramNames[i] == value.array[k].name)
                                    {
                                        if (typeInfo.isParam[i])
                                        {
                                            typeInfo.setValue[i](this, SetParams(typeInfo.fieldTypes[i], typeInfo.getValue[i](this), value.array[k].value));
                                        }
                                        else
                                        {
                                            typeInfo.setValue[i](this, value.array[k].value);
                                        }
                                        lastOffset = k + 1;
                                        if (lastOffset >= value.array.Length)
                                        {
                                            lastOffset -= value.array.Length;
                                        }
                                        break;
                                    }
                                }
                            }
                            catch (Exception)
                            {
                                throw new CastArgsException();
                            }
                        }
                    }
                    else
                    {
                        throw new CastArgsException();
                    }
                }
            }

            internal ParamTuple SetObjects(object value)
            {
                Objects = (Serialize)value;
                return this;
            }
        }

        static Delegate CreateNew<Delegate>(Type type)
        {
            var arguments = typeof(Delegate).GetGenericArguments();
            var paramTypes = new Type[arguments.Length - 1];
            Array.Copy(arguments, 0, paramTypes, 0, paramTypes.Length);
            var paramObjs = new ParameterExpression[paramTypes.Length];
            for (int i = 0; i < paramTypes.Length; i++)
            {
                paramObjs[i] = Expression.Parameter(paramTypes[i]);
            }
            var constructor = type.GetConstructor(InstanceFlag, null, paramTypes, null);
            var newBody = Expression.New(constructor, paramObjs);
            return Expression.Lambda<Delegate>(newBody, paramObjs).Compile();
        }

        static Func<object, object[], object> CreateCall(MethodInfo methodInfo)
        {
            var paramTypes = methodInfo.GetParameters();
            var instancetObj = Expression.Parameter(typeof(object));
            var paramObjs = Expression.Parameter(typeof(object[]));
            var fixedObjs = new ParameterExpression[paramTypes.Length];
            var expressions = new LinkedList<Expression>();
            for (int i = 0; i < paramTypes.Length; i++)
            {
                var paramType = paramTypes[i].ParameterType;
                fixedObjs[i] = Expression.Variable(paramType);
                var idxParam = Expression.ArrayIndex(paramObjs, Expression.Constant(i));
                if (ParamTuple.IsParamTuple(paramType))
                {
                    if (paramType.IsArray)
                    {
                        var tempArrayType = typeof(ParamTuple.TupleArray<>).MakeGenericType(paramType);
                        var tempArray = Expression.Variable(tempArrayType);
                        var newTempArray = Expression.Assign(tempArray, Expression.New(tempArrayType.GetConstructor(InstanceFlag, null, Type.EmptyTypes, null)));
                        var setObjects = Expression.Call(tempArray, tempArrayType.GetMethod("set_Objects", InstanceFlag), Expression.Convert(idxParam, typeof(ParamTuple.Serialize)));
                        var getArray = Expression.Assign(fixedObjs[i], Expression.Convert(Expression.Call(tempArray, tempArrayType.GetMethod("get_array", InstanceFlag)), paramType));
                        expressions.AddLast(Expression.Block(new ParameterExpression[] { tempArray }, newTempArray, setObjects, getArray));
                    }
                    else
                    {
                        expressions.AddLast(Expression.Call(Expression.Assign(fixedObjs[i], Expression.New(paramType.GetConstructor(InstanceFlag, null, Type.EmptyTypes, null))),
                            paramType.GetMethod("set_Objects", InstanceFlag), Expression.Convert(idxParam, typeof(ParamTuple.Serialize))));
                    }
                }
                else
                {
                    expressions.AddLast(Expression.Assign(fixedObjs[i], Expression.Convert(idxParam, paramType)));
                }
            }
            if (0 != expressions.Count)
            {
                expressions.AddLast(Expression.Constant(null));
                var castBody = Expression.Block(expressions);
                var newExp = Expression.New(typeof(CastArgsException).GetConstructor(InstanceFlag, null, Type.EmptyTypes, null));
                var throwBody = Expression.Block(Expression.Throw(newExp), Expression.Constant(null));
                expressions.Clear();
                expressions.AddLast(Expression.TryCatch(castBody, Expression.Catch(typeof(InvalidCastException), throwBody)));
            }
            var callExp = methodInfo.IsStatic ? Expression.Call(methodInfo, fixedObjs) : Expression.Call(Expression.Convert(instancetObj, methodInfo.DeclaringType), methodInfo, fixedObjs);
            if (methodInfo.ReturnType == typeof(void))
            {
                expressions.AddLast(callExp);
                expressions.AddLast(Expression.Constant(null));
            }
            else
            {
                expressions.AddLast(Expression.Convert(callExp, typeof(object)));
            }
            var callBody = Expression.Block(fixedObjs, expressions);
            return Expression.Lambda<Func<object, object[], object>>(callBody, instancetObj, paramObjs).Compile();
        }

        static Func<object, object> CreateObjectGetter(FieldInfo fieldInfo)
        {
            Type objType = fieldInfo.DeclaringType;
            var paramObj = Expression.Parameter(typeof(object));
            var fixedObj = Expression.Variable(objType);
            var cvtExp = fieldInfo.IsStatic ? null : Expression.Assign(fixedObj, Expression.Convert(paramObj, objType));
            var interField = Expression.Field(cvtExp, fieldInfo);
            var cvtToObj = Expression.Convert(interField, typeof(object));
            var getFieldBody = Expression.Block(new ParameterExpression[] { fixedObj }, cvtToObj);
            return Expression.Lambda<Func<object, object>>(getFieldBody, paramObj).Compile();
        }

        static Action<object, object> CreateObjectSetter(FieldInfo fieldInfo, bool checkParam)
        {
            Type objType = fieldInfo.DeclaringType;
            Type fieldType = fieldInfo.FieldType;
            var paramObj = Expression.Parameter(typeof(object));
            var fixedObj = Expression.Variable(objType);
            var valueObj = Expression.Parameter(typeof(object));
            var cvtExp = fieldInfo.IsStatic ? null : Expression.Assign(fixedObj, Expression.Convert(paramObj, objType));
            var interField = Expression.Field(cvtExp, fieldInfo);
            Expression setField;
            if (checkParam && ParamTuple.IsParamTuple(fieldType))
            {
                if (fieldType.IsArray)
                {
                    var tempArrayType = typeof(ParamTuple.TupleArray<>).MakeGenericType(fieldType);
                    var tempArray = Expression.Variable(tempArrayType);
                    var newTempArray = Expression.Assign(tempArray, Expression.New(tempArrayType.GetConstructor(InstanceFlag, null, Type.EmptyTypes, null)));
                    var setObjects = Expression.Call(tempArray, tempArrayType.GetMethod("set_Objects", InstanceFlag), Expression.Convert(valueObj, typeof(ParamTuple.Serialize)));
                    var getArray = Expression.Assign(interField, Expression.Convert(Expression.Call(tempArray, tempArrayType.GetMethod("get_array", InstanceFlag)), fieldType));
                    setField = Expression.Block(new ParameterExpression[] { tempArray }, newTempArray, setObjects, getArray);
                }
                else
                {
                    setField = Expression.Call(Expression.Assign(interField, Expression.New(fieldType.GetConstructor(InstanceFlag, null, Type.EmptyTypes, null))),
                        fieldType.GetMethod("set_Objects", InstanceFlag), Expression.Convert(valueObj, typeof(ParamTuple.Serialize)));
                }
            }
            else
            {
                setField = Expression.Assign(interField, Expression.Convert(valueObj, fieldType));
            }
            var setFieldBody = Expression.Block(new ParameterExpression[] { fixedObj }, setField);
            return Expression.Lambda<Action<object, object>>(setFieldBody, paramObj, valueObj).Compile();
        }

        public class Methods
        {
            static public Delegate Cast(Action handler) => handler;
            static public Delegate Cast<T0>(Action<T0> handler) => handler;
            static public Delegate Cast<T0, T1>(Action<T0, T1> handler) => handler;
            static public Delegate Cast<T0, T1, T2>(Action<T0, T1, T2> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3>(Action<T0, T1, T2, T3> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4>(Action<T0, T1, T2, T3, T4> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5>(Action<T0, T1, T2, T3, T4, T5> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6>(Action<T0, T1, T2, T3, T4, T5, T6> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7>(Action<T0, T1, T2, T3, T4, T5, T6, T7> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> handler) => handler;

            static public Delegate Cast<R>(Func<R> handler) => handler;
            static public Delegate Cast<T0, R>(Func<T0, R> handler) => handler;
            static public Delegate Cast<T0, T1, R>(Func<T0, T1, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, R>(Func<T0, T1, T2, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, R>(Func<T0, T1, T2, T3, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, R>(Func<T0, T1, T2, T3, T4, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, R>(Func<T0, T1, T2, T3, T4, T5, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, R>(Func<T0, T1, T2, T3, T4, T5, T6, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R> handler) => handler;

            struct BindObjInfo
            {
                public int task;
                public int argsCount;
                public Func<object, object[], object> method;
                public Func<object, object[], object> valueTask;
                public Func<object, object[], object> getResult;
            }

            [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Field)]
            public class AllowBind : Attribute
            {
                internal bool getter;
                internal bool setter;
                internal string rename;

                public AllowBind(bool getter = true, bool setter = true, string rename = null)
                {
                    this.getter = getter;
                    this.setter = setter;
                    this.rename = rename;
                }
            }

            [Serializable]
            public struct Name
            {
                internal string name;

                public Name(string name)
                {
                    this.name = name;
                }

                static public implicit operator string(Name rval)
                {
                    return rval.name;
                }
            }

            struct DelegateInfo
            {
                public Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler;
            }

            class ClassInfo
            {
                public bool isParam;
                public bool isStatic;
                public bool isAllowBind;
                public int arrayDim;
                public Type fieldType;
                public Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler;
            }

            static long _nameid = DateTime.Now.Ticks;
            static ConcurrentDictionary<Type, DelegateInfo> _delegateMap = new ConcurrentDictionary<Type, DelegateInfo>();
            static ConcurrentDictionary<Type, Dictionary<string, ClassInfo>> _classsMap = new ConcurrentDictionary<Type, Dictionary<string, ClassInfo>>();
            ConcurrentDictionary<string, tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand>> _methodsMap =
                new ConcurrentDictionary<string, tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand>>();

            static public Name GenName
            {
                get
                {
                    return new Name(Interlocked.Increment(ref _nameid).ToString());
                }
            }

            static public bool CheckName(string name)
            {
                if (name?.Length == 0)
                {
                    return false;
                }
                for (int i = 0; i < name.Length; i++)
                {
                    char c = name[i];
                    if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')))
                    {
                        return false;
                    }
                }
                return true;
            }

            public void Bind(string name, Action handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0>(string name, Action<T0> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1>(string name, Action<T0, T1> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2>(string name, Action<T0, T1, T2> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3>(string name, Action<T0, T1, T2, T3> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4>(string name, Action<T0, T1, T2, T3, T4> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5>(string name, Action<T0, T1, T2, T3, T4, T5> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6>(string name, Action<T0, T1, T2, T3, T4, T5, T6> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);

            public void Bind<R>(string name, Func<R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, R>(string name, Func<T0, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, R>(string name, Func<T0, T1, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, R>(string name, Func<T0, T1, T2, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, R>(string name, Func<T0, T1, T2, T3, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, R>(string name, Func<T0, T1, T2, T3, T4, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, R>(string name, Func<T0, T1, T2, T3, T4, T5, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind(string name, Delegate handler, shared_strand runStrand = null) => Bind(name, handler, null, null, runStrand);

            internal void Bind(string name, Delegate handler, wait_group stopWg, wait_group endWg, shared_strand runStrand)
            {
                if (!CheckName(name))
                {
                    assert.check(false, $"Bind 命名错误 {name}");
                    return;
                }
                DelegateInfo delegateInfo = GetDelegateInfo(handler.GetType());
                Add(name, (_1, _2) => delegateInfo.handler(handler, stopWg, endWg, _1, _2), runStrand);
            }

            static private DelegateInfo GetDelegateInfo(Type type)
            {
                if (_delegateMap.TryGetValue(type, out var delegateInfo))
                {
                    return delegateInfo;
                }
                MethodInfo method = type.GetMethod("Invoke");
                BindObjInfo methodInfo = new BindObjInfo { task = 0 };
                methodInfo.argsCount = method.GetParameters().Length;
                methodInfo.method = CreateCall(method);
                Type returnType = method.ReturnType;
                string returnTypeName = returnType.Name;
                if ("Task" == returnTypeName || "Task`1" == returnTypeName)
                {
                    methodInfo.task = 1;
                    MethodInfo getResult = returnType.GetMethod("get_Result");
                    if (null != getResult)
                    {
                        methodInfo.getResult = CreateCall(getResult);
                    }
                }
                else if ("ValueTask" == returnTypeName || "ValueTask`1" == returnTypeName)
                {
                    methodInfo.task = 2;
                    methodInfo.valueTask = CreateCall(returnType.GetMethod("AsTask"));
                    methodInfo.getResult = CreateCall(returnType.GetMethod("GetResult"));
                }
                delegateInfo = new DelegateInfo();
                delegateInfo.handler = async delegate (object handler, wait_group stopWg, wait_group endWg, async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    if (null != endWg && endWg.cancel)
                    {
                        return;
                    }
                    if (methodInfo.argsCount != args.Length)
                    {
                        resWrap.value2 = ReplyState.ArgsCountError;
                        return;
                    }
                    wait_group.cancel_token cancelToken = default;
                    try
                    {
                        if (null != endWg)
                        {
                            endWg.add();
                            if (endWg.cancel)
                            {
                                return;
                            }
                        }
                        if (null != stopWg)
                        {
                            generator self = generator.self;
                            cancelToken = stopWg.async_wait(() => self.stop());
                        }
                        switch (methodInfo.task)
                        {
                            case 0:
                                {
                                    resWrap.value1 = methodInfo.method(handler, args);
                                }
                                break;
                            case 1:
                                {
                                    Task task = (Task)methodInfo.method(handler, args);
                                    await task;
                                    if (null != methodInfo.getResult)
                                    {
                                        resWrap.value1 = methodInfo.getResult(task, new object[0]);
                                    }
                                }
                                break;
                            case 2:
                                {
                                    object result = methodInfo.method(handler, args);
                                    Task task = (Task)methodInfo.valueTask(result, new object[0]);
                                    if (null != task)
                                    {
                                        await task;
                                    }
                                    resWrap.value1 = methodInfo.getResult(result, new object[0]);
                                }
                                break;
                        }
                    }
                    catch (CastArgsException)
                    {
                        resWrap.value2 = ReplyState.ArgsTypeError;
                    }
                    finally
                    {
                        stopWg?.cancel_wait(cancelToken);
                        endWg?.done();
                    }
                };
                _delegateMap.TryAdd(type, delegateInfo);
                return delegateInfo;
            }

            public string[] BindStatic(string name, Type type, shared_strand runStrand = null)
            {
                return BindClass(name, type, null, false, null, null, runStrand);
            }

            public string[] BindObj<T>(string name, T obj, bool declaredOnly = true, shared_strand runStrand = null)
            {
                return BindClass(name, typeof(T), obj, declaredOnly, null, null, runStrand);
            }

            static public void AssertName()
            {
                Assembly assembly = Assembly.GetCallingAssembly();
                Type[] allTypes = assembly.GetTypes();
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    GetClassInfo(type);
                }
            }

            static string ParseArray(string name, out int[][] indices)
            {
                indices = null;
                int l = name.Length;
                if (l < 4)
                {
                    return name;
                }
                if (name[l - 1] != ']')
                {
                    return name;
                }
                int leftIdx = name.IndexOf('[');
                if (!(leftIdx > 0 && leftIdx < l - 2))
                {
                    throw new CastArgsException { state = ReplyState.IndexError };
                }
                int dimCount = 0;
                for (int i = leftIdx; i < l; i++)
                {
                    if (name[i] == '[')
                    {
                        dimCount++;
                    }
                }
                indices = new int[dimCount][];
                dimCount = 0;
                for (int i = leftIdx; i < l; i++)
                {
                    char c = name[i];
                    if (c == '[')
                    {
                        int rankCount = 1;
                        for (int j = i + 1; j < l; j++)
                        {
                            c = name[j];
                            if (c == ']')
                            {
                                break;
                            }
                            if (c == ',')
                            {
                                rankCount++;
                            }
                            else if (!((c >= '0' && c <= '9') || c == ' ' || c == '\t' || c == '-'))
                            {
                                throw new CastArgsException { state = ReplyState.IndexError };
                            }
                        }
                        int[] index = indices[dimCount] = new int[rankCount];
                        rankCount = 0;
                        int number = 0;
                        bool neg = false;
                        bool num = false;
                        bool space = false;
                        for (i++; i < l; i++)
                        {
                            c = name[i];
                            if (c >= '0' && c <= '9')
                            {
                                if (space)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                number = number * 10 + (c - '0');
                                if (number < 0)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                num = true;
                            }
                            else if (c == ',' || c == ']')
                            {
                                if (!num)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                index[rankCount] = neg ? -number : number;
                                if (c == ']')
                                {
                                    break;
                                }
                                number = 0;
                                rankCount++;
                                neg = false;
                                num = false;
                                space = false;
                            }
                            else if (c == '-')
                            {
                                if (neg || num)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                neg = true;
                            }
                            else if (c == ' ' || c == '\t')
                            {
                                if (neg || num)
                                {
                                    space = true;
                                }
                            }
                        }
                        dimCount++;
                    }
                    else if (!(c == ' ' || c == '\t'))
                    {
                        throw new CastArgsException { state = ReplyState.IndexError };
                    }
                }
                return name.Substring(0, leftIdx);
            }

            internal string[] BindClass(string name, Type type, object obj, bool declaredOnly, wait_group stopWg, wait_group endWg, shared_strand runStrand)
            {
                if (!CheckName(name))
                {
                    assert.check(false, $"BindClass 命名错误 {name}");
                    return null;
                }
                Dictionary<string, ClassInfo> classInfo = GetClassInfo(type);
                if (null == classInfo)
                {
                    assert.check(false, $"{name} 绑定了没有使用 AllowBind 特性的对象 {type.FullName}");
                    return null;
                }
                Type itType = type;
                Dictionary<string, ClassInfo> itClassInfo = classInfo;
                LinkedList<string> names = new LinkedList<string>();
                do
                {
                    if (null != itClassInfo)
                    {
                        foreach (var item in itClassInfo)
                        {
                            if (null == obj && !item.Value.isStatic)
                            {
                                continue;
                            }
                            Add(names.AddLast($"{name}.{item.Key}").Value, (_1, _2) => item.Value.handler(obj, stopWg, endWg, _1, _2), runStrand);
                        }
                        itClassInfo = null;
                    }
                    if (!declaredOnly)
                    {
                        itType = itType.BaseType;
                        if (null != itType)
                        {
                            itClassInfo = GetClassInfo(itType);
                        }
                    }
                    else
                    {
                        itType = null;
                    }
                } while (null != itClassInfo || null != itType);
                Add(names.AddLast(name).Value, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    object obj_ = obj;
                    Type type_ = type;
                    if (null == resWrap.value1)
                    {
                        resWrap.value2 = ReplyState.NotFound;
                        return generator.non_async();
                    }
                    string[] fields = (string[])resWrap.value1;
                    for (int i = 1; i < fields.Length - 1; i++)
                    {
                        string field_ = ParseArray(fields[i], out int[][] indices);
                        resWrap.value1 = null;
                        resWrap.value2 = ReplyState.Success;
                        ClassInfo field = CheckMethod(type_, null == obj_, $"get@{field_}", declaredOnly);
                        field.handler(obj_, stopWg, endWg, resWrap, new object[0]);
                        if (resWrap.value2 != ReplyState.Success)
                        {
                            return generator.non_async();
                        }
                        obj_ = resWrap.value1;
                        type_ = field.fieldType;
                        if (null == indices)
                        {
                            continue;
                        }
                        if (field.arrayDim < indices.Length)
                        {
                            resWrap.value2 = ReplyState.NotFound;
                            return generator.non_async();
                        }
                        try
                        {
                            for (int j = 0; j < indices.Length; j++)
                            {
                                obj_ = GetValue((Array)obj_, indices[j]);
                            }
                        }
                        catch (IndexOutOfRangeException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (ArgumentException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (CastArgsException ec)
                        {
                            resWrap.value2 = ec.state;
                            return generator.non_async();
                        }
                        catch (Exception)
                        {
                            resWrap.value2 = ReplyState.ArgsTypeError;
                            return generator.non_async();
                        }
                    }
                    {
                        string field_ = ParseArray(fields[fields.Length - 1], out int[][] indices);
                        if (null == indices)
                        {
                            resWrap.value1 = null;
                            resWrap.value2 = ReplyState.Success;
                            ClassInfo method = CheckMethod(type_, null == obj_, field_, declaredOnly);
                            return method.handler(obj_, stopWg, endWg, resWrap, args);
                        }
                        bool isGet;
                        bool getLength = false;
                        if (HeadEq(field_, "set@"))
                        {
                            if (1 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            field_ = $"get@{field_.Substring(4)}";
                            isGet = false;
                        }
                        else if (HeadEq(field_, "get@"))
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            isGet = true;
                        }
                        else if (HeadEq(field_, "len@"))
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            field_ = $"get@{field_.Substring(4)}";
                            isGet = true;
                            getLength = true;
                        }
                        else
                        {
                            resWrap.value2 = ReplyState.NotFound;
                            return generator.non_async();
                        }
                        resWrap.value1 = null;
                        resWrap.value2 = ReplyState.Success;
                        ClassInfo field = CheckMethod(type_, null == obj_, field_, declaredOnly);
                        if (field.arrayDim < indices.Length)
                        {
                            resWrap.value2 = ReplyState.NotFound;
                            return generator.non_async();
                        }
                        field.handler(obj_, stopWg, endWg, resWrap, new object[0]);
                        if (resWrap.value2 != ReplyState.Success)
                        {
                            return generator.non_async();
                        }
                        try
                        {
                            obj_ = resWrap.value1;
                            resWrap.value1 = null;
                            Array objs = (Array)obj_;
                            for (int j = 0; j < indices.Length - 1; j++)
                            {
                                objs = (Array)GetValue(objs, indices[j]);
                            }
                            if (isGet)
                            {
                                object result = GetValue(objs, indices[indices.Length - 1]);
                                if (getLength)
                                {
                                    if (field.arrayDim == indices.Length)
                                    {
                                        resWrap.value2 = ReplyState.NotFound;
                                        return generator.non_async();
                                    }
                                    Array array = (Array)result;
                                    if (null == array)
                                    {
                                        resWrap.value2 = ReplyState.IsNull;
                                        return generator.non_async();
                                    }
                                    int rank = array.Rank;
                                    if (1 == rank)
                                    {
                                        resWrap.value1 = array.GetLength(0);
                                    }
                                    else
                                    {
                                        int[] shape = new int[rank];
                                        for (int j = 0; j < rank; j++)
                                        {
                                            shape[j] = array.GetLength(j);
                                        }
                                        resWrap.value1 = shape;
                                    }
                                }
                                else
                                {
                                    resWrap.value1 = result;
                                }
                            }
                            else
                            {
                                if (field.isParam)
                                {
                                    SetValue(objs, ParamTuple.GetTypeInfo(field.fieldType).newTuple().SetObjects(args[0]), indices[indices.Length - 1]);
                                }
                                else
                                {
                                    SetValue(objs, args[0], indices[indices.Length - 1]);
                                }
                            }
                            return generator.non_async();
                        }
                        catch (IndexOutOfRangeException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (ArgumentException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (CastArgsException ec)
                        {
                            resWrap.value2 = ec.state;
                            return generator.non_async();
                        }
                        catch (Exception)
                        {
                            resWrap.value2 = ReplyState.ArgsTypeError;
                            return generator.non_async();
                        }
                    }
                }, runStrand);
                return names.ToArray();
            }

            static private bool HeadEq(string str, string head)
            {
                if (str.Length + 1 < head.Length)
                {
                    return false;
                }
                for (int i = 0; i < head.Length; i++)
                {
                    if (str[i] != head[i])
                    {
                        return false;
                    }
                }
                return true;
            }

            static private object GetValue(Array array, int[] indices)
            {
                if (null == array)
                {
                    throw new CastArgsException { state = ReplyState.IsNull };
                }
                for (int k = 0; k < indices.Length; k++)
                {
                    if (indices[k] < 0)
                    {
                        indices[k] = array.GetLength(k) + indices[k];
                    }
                }
                return array.GetValue(indices);
            }

            static private void SetValue(Array array, object value, int[] indices)
            {
                if (null == array)
                {
                    throw new CastArgsException { state = ReplyState.IsNull };
                }
                for (int k = 0; k < indices.Length; k++)
                {
                    if (indices[k] < 0)
                    {
                        indices[k] = array.GetLength(k) + indices[k];
                    }
                }
                array.SetValue(value, indices);
            }

            static private ClassInfo CheckMethod(Type type, bool isNull, string method, bool declaredOnly)
            {
                ClassInfo classInfo = GetMethod(type, method, declaredOnly);
                if (null == classInfo)
                {
                    throw new CastArgsException { state = ReplyState.NotFound };
                }
                if (isNull && !classInfo.isStatic)
                {
                    throw new CastArgsException { state = ReplyState.IsNull };
                }
                return classInfo;
            }

            static private ClassInfo GetMethod(Type type, string method, bool declaredOnly)
            {
                var classInfo = GetClassInfo(type);
                if (null == classInfo)
                {
                    return null;
                }
                if (classInfo.TryGetValue(method, out var value))
                {
                    return value;
                }
                if (declaredOnly)
                {
                    return null;
                }
                type = type.BaseType;
                if (null == type)
                {
                    return null;
                }
                return GetMethod(type, method, false);
            }

            static private Dictionary<string, ClassInfo> GetClassInfo(Type type)
            {
                if (_classsMap.TryGetValue(type, out var classInfo))
                {
                    return classInfo;
                }
                if (!Attribute.IsDefined(type, typeof(AllowBind), false))
                {
                    return null;
                }
                classInfo = new Dictionary<string, ClassInfo>();
                MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | InstanceFlag);
                var overrideMethod = new Dictionary<string, LinkedList<BindObjInfo>>();
                for (int i = 0; i < methods.Length; i++)
                {
                    MethodInfo method = methods[i];
                    AllowBind allowBind = (AllowBind)Attribute.GetCustomAttribute(method, typeof(AllowBind), false);
                    if (null == allowBind)
                    {
                        continue;
                    }
                    BindObjInfo methodInfo = new BindObjInfo { task = 0 };
                    methodInfo.argsCount = method.GetParameters().Length;
                    methodInfo.method = CreateCall(method);
                    Type returnType = method.ReturnType;
                    string returnTypeName = returnType.Name;
                    if ("Task" == returnTypeName || "Task`1" == returnTypeName)
                    {
                        methodInfo.task = 1;
                        MethodInfo getResult = returnType.GetMethod("get_Result");
                        if (null != getResult)
                        {
                            methodInfo.getResult = CreateCall(getResult);
                        }
                    }
                    else if ("ValueTask" == returnTypeName || "ValueTask`1" == returnTypeName)
                    {
                        methodInfo.task = 2;
                        methodInfo.valueTask = CreateCall(returnType.GetMethod("AsTask"));
                        methodInfo.getResult = CreateCall(returnType.GetMethod("GetResult"));
                    }
                    string methodName = allowBind.rename ?? method.Name;
                    if (!CheckName(methodName))
                    {
                        assert.check(false, $"{type.FullName} 方法命名错误 {methodName}\r\n{type.Assembly.FullName}");
                    }
                    LinkedList<BindObjInfo> sameName;
                    if (!overrideMethod.TryGetValue(methodName, out sameName))
                    {
                        sameName = new LinkedList<BindObjInfo>();
                        overrideMethod.Add(methodName, sameName);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = async (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (null != endWg && endWg.cancel)
                            {
                                return;
                            }
                            wait_group.cancel_token cancelToken = default;
                            try
                            {
                                if (null != endWg)
                                {
                                    endWg.add();
                                    if (endWg.cancel)
                                    {
                                        return;
                                    }
                                }
                                if (null != stopWg)
                                {
                                    generator self = generator.self;
                                    cancelToken = stopWg.async_wait(() => self.stop());
                                }
                                bool countError = true;
                                foreach (BindObjInfo item in sameName)
                                {
                                    if (item.argsCount != args.Length)
                                    {
                                        continue;
                                    }
                                    try
                                    {
                                        countError = false;
                                        switch (item.task)
                                        {
                                            case 0:
                                                {
                                                    resWrap.value1 = item.method(obj, args);
                                                }
                                                break;
                                            case 1:
                                                {
                                                    Task task = (Task)item.method(obj, args);
                                                    await task;
                                                    if (null != item.getResult)
                                                    {
                                                        resWrap.value1 = item.getResult(task, new object[0]);
                                                    }
                                                }
                                                break;
                                            case 2:
                                                {
                                                    object result = item.method(obj, args);
                                                    Task task = (Task)item.valueTask(result, new object[0]);
                                                    if (null != task)
                                                    {
                                                        await task;
                                                    }
                                                    resWrap.value1 = item.getResult(result, new object[0]);
                                                }
                                                break;
                                        }
                                        return;
                                    }
                                    catch (CastArgsException) { }
                                }
                                resWrap.value2 = countError ? ReplyState.ArgsCountError : ReplyState.ArgsTypeError;
                            }
                            finally
                            {
                                stopWg?.cancel_wait(cancelToken);
                                endWg?.done();
                            }
                        };
                        classInfo.Add(methodName, new ClassInfo { isStatic = method.IsStatic, handler = handler });
                    }
                    sameName.AddLast(methodInfo);
                }
                FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | InstanceFlag);
                for (int i = 0; i < fields.Length; i++)
                {
                    FieldInfo field = fields[i];
                    AllowBind allowBind = (AllowBind)Attribute.GetCustomAttribute(field, typeof(AllowBind), false);
                    if (null == allowBind)
                    {
                        continue;
                    }
                    Type fieldType = field.FieldType;
                    int arrayDim = 0;
                    bool isArray = fieldType.IsArray;
                    bool arrayIt = isArray;
                    while (arrayIt)
                    {
                        arrayDim++;
                        fieldType = fieldType.GetElementType();
                        arrayIt = fieldType.IsArray;
                    }
                    bool isParam = fieldType.IsSubclassOf(typeof(ParamTuple));
                    bool isAllowBind = Attribute.IsDefined(fieldType, typeof(AllowBind), false);
                    string fieldName = allowBind.rename ?? field.Name;
                    if (!CheckName(fieldName))
                    {
                        assert.check(false, $"{type.FullName} 属性命名错误 {fieldName}\r\n{type.Assembly.FullName}");
                    }
                    Func<object, object> getValue = null;
                    if (isArray)
                    {
                        getValue = CreateObjectGetter(field);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            Array array = (Array)getValue(obj);
                            if (null == array)
                            {
                                resWrap.value2 = ReplyState.IsNull;
                                return generator.non_async();
                            }
                            int rank = array.Rank;
                            if (1 == rank)
                            {
                                resWrap.value1 = array.GetLength(0);
                            }
                            else
                            {
                                int[] shape = new int[rank];
                                for (int j = 0; j < rank; j++)
                                {
                                    shape[j] = array.GetLength(j);
                                }
                                resWrap.value1 = shape;
                            }
                            return generator.non_async();
                        };
                        try
                        {
                            classInfo.Add($"len@{fieldName}", new ClassInfo { arrayDim = arrayDim, isParam = isParam, isStatic = field.IsStatic, isAllowBind = isAllowBind, fieldType = fieldType, handler = handler });
                        }
                        catch (ArgumentException)
                        {
                            assert.check(false, $"{type.FullName} 属性名称 {fieldName} 重复\r\n{type.Assembly.FullName}");
                        }
                    }
                    if (allowBind.getter)
                    {
                        getValue = getValue ?? CreateObjectGetter(field);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            resWrap.value1 = getValue(obj);
                            return generator.non_async();
                        };
                        try
                        {
                            classInfo.Add($"get@{fieldName}", new ClassInfo { arrayDim = arrayDim, isParam = isParam, isStatic = field.IsStatic, isAllowBind = isAllowBind, fieldType = fieldType, handler = handler });
                        }
                        catch (ArgumentException)
                        {
                            assert.check(false, $"{type.FullName} 属性名称 {fieldName} 重复\r\n{type.Assembly.FullName}");
                        }
                    }
                    if (allowBind.setter)
                    {
                        Action<object, object> setValue = CreateObjectSetter(field, true);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (1 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            if (null != endWg && endWg.cancel)
                            {
                                return generator.non_async();
                            }
                            try
                            {
                                if (null != endWg)
                                {
                                    endWg.add();
                                    if (endWg.cancel)
                                    {
                                        return generator.non_async();
                                    }
                                }
                                setValue(obj, args[0]);
                            }
                            catch (InvalidCastException)
                            {
                                resWrap.value2 = ReplyState.ArgsTypeError;
                            }
                            catch (CastArgsException)
                            {
                                resWrap.value2 = ReplyState.ArgsTypeError;
                            }
                            finally
                            {
                                endWg?.done();
                            }
                            return generator.non_async();
                        };
                        try
                        {
                            classInfo.Add($"set@{fieldName}", new ClassInfo { arrayDim = arrayDim, isParam = isParam, isStatic = field.IsStatic, isAllowBind = isAllowBind, fieldType = fieldType, handler = handler });
                        }
                        catch (ArgumentException)
                        {
                            assert.check(false, $"{type.FullName} 属性名称 {fieldName} 重复\r\n{type.Assembly.FullName}");
                        }
                    }
                }
                _classsMap.TryAdd(type, classInfo);
                return classInfo;
            }

            private void Add(string name, Func<async_result_wrap<object, ReplyState>, object[], Task> handler, shared_strand runStrand)
            {
                if (!_methodsMap.TryAdd(name, tuple.make(handler, runStrand)))
                {
                    assert.check(false, $"Bind 重复的方法名 {name}");
                }
            }

            internal bool Get(string name, out tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand> handler)
            {
                return _methodsMap.TryGetValue(name, out handler);
            }

            public bool Remove(string name)
            {
                if (name?.Length > 0)
                {
                    return _methodsMap.TryRemove(name, out var _);
                }
                return false;
            }

            public void Remove(params string[] names)
            {
                foreach (var name in names)
                {
                    Remove(name);
                }
            }

            public void Clear()
            {
                _methodsMap.Clear();
            }
        }

        public class RpcException : Exception
        {
            public ReplyState code;

            public RpcException(ReplyState st)
            {
                code = st;
            }
        }

        public struct Result
        {
            public ReplyState state;
            public string message;
            public object result;

            static public implicit operator ReplyState(Result rval)
            {
                return rval.state;
            }

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }

            public bool Success
            {
                get
                {
                    return state == ReplyState.Success;
                }
            }
        }

        public struct Result<R>
        {
            public ReplyState state;
            public string message;
            public R result;

            static public implicit operator R(Result<R> rval)
            {
                rval.Check();
                return rval.result;
            }

            static public implicit operator ReplyState(Result<R> rval)
            {
                return rval.state;
            }

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }

            public bool Success
            {
                get
                {
                    return state == ReplyState.Success;
                }
            }
        }

        class OverSend
        {
            public bool closed;
            public int count;
            public wait_group wg;
            public LinkedList<tuple<Func<bool, Task>, RecvName>> actions;

            public OverSend()
            {
                closed = false;
                count = 0;
                wg = new wait_group(1, true);
                actions = new LinkedList<tuple<Func<bool, Task>, RecvName>>();
            }

            public RecvName[] Sends()
            {
                if (0 == count)
                {
                    return null;
                }
                RecvName[] sends = new RecvName[count];
                int num = 0;
                foreach (var item in actions)
                {
                    if (item.value2.count >= 0)
                    {
                        sends[num++] = item.value2;
                    }
                }
                return sends;
            }

            public void Close()
            {
                closed = true;
                wg.done();
            }
        }

        public struct RpcCancel
        {
            internal wait_group wg;

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void AppendNotify(Action notify)
            {
                wg.async_wait(notify);
            }

            public Task Wait()
            {
                return generator.wait_group(wg);
            }

            public ValueTask<bool> Wait(int ms)
            {
                return generator.timed_wait_group(ms, wg);
            }
        }

        public struct OverCancel
        {
            internal wait_group wg;

            static internal OverCancel Make()
            {
                return new OverCancel
                {
                    wg = new wait_group(1, true)
                };
            }

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void Cancel()
            {
                wg.force();
            }
        }

        public class CancelException : Exception
        {
            internal CancelException() { }
        }

        [Serializable]
        internal struct RecvName
        {
            public long id;
            public long count;
            public int segment;

            public bool Check()
            {
                return id > 0 && count >= 0 && segment >= 0;
            }
        }

        internal struct RecvParam
        {
            public int timed;
            public int count;
            public long offset;
            public byte[] buff;
            public IntPtr pointer;
        }

        public class OverRecv
        {
            internal OverRecv(RecvName recvName, Session session, csp_chan<int, RecvParam> csp)
            {
                _csp = csp;
                _session = session;
                _id = recvName.id;
                _count = recvName.count;
                _segment = recvName.segment;
                _offset = 0;
                _multiSign = 0;
                _index = -1;
                _cancel = false;
            }

            internal csp_chan<int, RecvParam> _csp;
            internal Session _session;
            internal long _id;
            internal long _offset;
            internal long _count;
            internal int _index;
            internal int _segment;
            internal int _multiSign;
            internal bool _cancel;

            public bool Cancel => _cancel;
            public bool Big => _count > int.MaxValue;
            public bool Full => _offset == _count;
            public bool Completed => _offset == _count || _cancel;
            public long Offset => _offset;
            public long Length => _count;
            public int Segment => _segment;
            public int Index => _index;

            public Task<csp_invoke_wrap<int>> Recv(ArraySegment<byte> buff) => _session.Recv(this, buff);
            public Task<csp_invoke_wrap<int>> Recv(byte[] buff) => _session.Recv(this, buff);
            public Task<csp_invoke_wrap<int>> Recv(byte[] buff, int offset, int count) => _session.Recv(this, buff, offset, count);
            public Task<csp_invoke_wrap<int>> Recv(IntPtr pointer, long offset, int count) => _session.Recv(this, pointer, offset, count);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, ArraySegment<byte> buff) => _session.TimedRecv(this, timed, buff);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, byte[] buff) => _session.TimedRecv(this, timed, buff);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, byte[] buff, int offset, int count) => _session.TimedRecv(this, timed, buff, offset, count);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, IntPtr pointer, long offset, int count) => _session.TimedRecv(this, timed, pointer, offset, count);
            public Task<csp_invoke_wrap<int>> TimedRecv(tuple<int, int> timed, ArraySegment<byte> buff) => _session.TimedRecv(this, timed, buff);
            public Task<csp_invoke_wrap<int>> TimedRecv(tuple<int, int> timed, byte[] buff) => _session.TimedRecv(this, timed, buff);
            public Task<csp_invoke_wrap<int>> TimedRecv(tuple<int, int> timed, byte[] buff, int offset, int count) => _session.TimedRecv(this, timed, buff, offset, count);
            public Task<csp_invoke_wrap<int>> TimedRecv(tuple<int, int> timed, IntPtr pointer, long offset, int count) => _session.TimedRecv(this, timed, pointer, offset, count);
        }

        class OverSendState
        {
            public SendName name;
            public long maxCount;
            public long count;
            public ValueTask<csp_invoke_wrap<void_type>> task;
        }

        internal class SendName
        {
            static long _inc = 0;
            public long _id;
            public bool _done;

            public SendName()
            {
                _id = Interlocked.Increment(ref _inc);
            }
        }

        public class RecvDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            bool error;

            public RecvDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public RecvDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                error = false;
            }

            public void Async(Action handler)
            {
                assert.check(task.is_done, "RecvDoubleBuffer 异步任务未结束");
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] WriteData
            {
                get
                {
                    return buff1;
                }
            }

            public byte[] RecvBuff
            {
                get
                {
                    return buff2;
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public class SendDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            int count;
            bool error;

            public SendDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public SendDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                count = 0;
                error = false;
            }

            public void Async(Func<int> handler)
            {
                assert.check(task.is_done, "SendDoubleBuffer 异步任务未结束");
                count = 0;
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        count = handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] ReadBuff
            {
                get
                {
                    return buff1;
                }
            }

            public ArraySegment<byte> SendData
            {
                get
                {
                    return new ArraySegment<byte>(buff2, 0, count);
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public class Session
        {
            enum DataType : byte
            {
                Keep,
                NoKeep,
                Close,
                Request,
                RequestCancel,
                Reply,
                Bin,
                BinCancel,
            }

            [Serializable]
            struct Request
            {
                public bool reply;
                public string name;
                public RecvName[] sends;
            }

            [Serializable]
            struct Reply
            {
                public ReplyState state;
                public string message;
            }

            struct SendByteParam
            {
                public SendName name;
                public int timed;
                public int index;
                public int count;
                public int offset;
                public byte[] data;
            }

            struct SendPtrParam
            {
                public SendName name;
                public int timed;
                public int index;
                public int count;
                public long offset;
                public IntPtr pointer;
            }

            struct SendFileParam
            {
                public SendName name;
                public int timed;
                public int index;
                public int count;
                public long offset;
                public SafeFileHandle file;
            }

            struct RpcParam
            {
                public long id;
                public int timed;
                public object[] args;
                public Request request;
                public OverSend overSend;
                public OverCancel overCancel;
            }

            struct RecvList
            {
                public OverRecv[] recvs;
            }

            class OverCallbackList
            {
                public wait_group stopWg;
                public wait_group endWg;
                public LinkedList<string> names;
            }

            static generator.local<Session> _session = new generator.local<Session>();
            static byte[] _lostBinBuff = new byte[1024 * 1024];
            static long _idCount = DateTime.Now.Ticks;
            static int _keep = 10000;

            int _exitCode;
            socket _socket;
            Methods _methods;
            generator _action;
            shared_strand[] _strands;
            generator.local<OverSend> _overSend;
            generator.local<RecvList> _recvList;
            generator.local<RpcCancel> _rpcCancel;
            generator.local<OverCancel> _overCancel;
            generator.local<OverSendState> _overSendState;
            generator.local<OverCallbackList> _overCallbackList;
            csp_chan<Result, RpcParam> _rpcChan;
            csp_chan<void_type, SendName> _cancelSendChan;
            csp_chan<void_type, SendByteParam> _sendByteChan;
            csp_chan<void_type, SendPtrParam> _sendPtrChan;
            csp_chan<void_type, SendFileParam> _sendFileChan;
            chan<OverRecv> _namedRecvChan;
            chan<DataType> _remoteCmdChan;
            chan<long> _cancelRpcChan;

            public Session(shared_strand[] strands, socket socket, Methods methods)
            {
                assert.check((socket is socket_tcp) || (socket is socket_pipe), "Rpc.Session 只能为 socket_tcp 或 socket_pipe");
                _socket = socket;
                _methods = methods;
                _strands = strands;
                _exitCode = (int)ExitCode.Undefined;
                _overSend = new generator.local<OverSend>();
                _recvList = new generator.local<RecvList>();
                _rpcCancel = new generator.local<RpcCancel>();
                _overCancel = new generator.local<OverCancel>();
                _overSendState = new generator.local<OverSendState>();
                _overCallbackList = new generator.local<OverCallbackList>();
                _rpcChan = new csp_chan<Result, RpcParam>(_strands[0]);
                _cancelSendChan = new csp_chan<void_type, SendName>(_strands[0]);
                _sendByteChan = new csp_chan<void_type, SendByteParam>(_strands[0]);
                _sendPtrChan = new csp_chan<void_type, SendPtrParam>(_strands[0]);
                _sendFileChan = new csp_chan<void_type, SendFileParam>(_strands[0]);
                _namedRecvChan = chan<OverRecv>.make(_strands[0], -1);
                _remoteCmdChan = chan<DataType>.make(_strands[0], -1);
                _cancelRpcChan = chan<long>.make(_strands[0], -1);
                _action = generator.make(_strands[0], () => Run(), delegate ()
                {
                    _socket.close();
                    _rpcChan.close();
                    _cancelSendChan.close();
                    _sendByteChan.close();
                    _sendPtrChan.close();
                    _sendFileChan.close();
                    _namedRecvChan.close();
                    _remoteCmdChan.close();
                    _cancelRpcChan.close();
                });
            }

            public Session(shared_strand strand, socket socket, Methods methods)
                : this(new shared_strand[] { strand }, socket, methods) { }

            public void Start()
            {
                _action.run();
            }

            public void Close()
            {
                SetCode(ExitCode.SessionClose);
                _action.stop();
                _strands[0].dispatch(() => _socket.close());
            }

            public void AppendNotify(Action notify)
            {
                _action.append_stop_callback(notify);
            }

            public Task Join()
            {
                return generator.wait_other(_action);
            }

            public ValueTask<bool> Join(int ms)
            {
                return generator.timed_wait_other(ms, _action);
            }

            public bool Closed
            {
                get
                {
                    return _action.is_completed();
                }
            }

            public ExitCode Code
            {
                get
                {
                    return (ExitCode)_exitCode;
                }
            }

            public Methods Methods
            {
                get
                {
                    return _methods;
                }
            }

            static private void Swap<T>(ref T a, ref T b)
            {
                T t = a;
                a = b;
                b = t;
            }

            static private unsafe void ReadHead(byte[] recvHead, out long id, out int len1, out int len2, out DataType type)
            {
                fixed (byte* ptr = recvHead)
                {
                    id = *(long*)ptr;
                    len1 = *(int*)(ptr + 8);
                    len2 = *(int*)(ptr + 12);
                    type = (DataType)(byte)*(ptr + 16);
                }
            }

            static private unsafe void WriteHead(byte[] sendHead, long id, int len1, int len2, DataType type)
            {
                fixed (byte* ptr = sendHead)
                {
                    *(long*)ptr = id;
                    *(int*)(ptr + 8) = len1;
                    *(int*)(ptr + 12) = len2;
                    *(ptr + 16) = (byte)type;
                }
            }

            static public Session Self
            {
                get
                {
                    _session.get(out Session self);
                    return self;
                }
            }

            static public RpcCancel CancelWait()
            {
                Session self = Self;
                assert.check(null != self, "不在 Rpc.Session 上下文中");
                self._rpcCancel.get(out RpcCancel value);
                return value;
            }

            static public OverRecv[] OverRecv()
            {
                Session self = Self;
                assert.check(null != self, "不在 Rpc.Session 上下文中");
                if (!self._recvList.get(out RecvList value))
                {
                    return null;
                }
                return value.recvs;
            }

            static public void ThrowCancel()
            {
                Session self = Self;
                assert.check(null != self, "不在 Rpc.Session 上下文中");
                throw new CancelException();
            }

            static public void DisableKeep()
            {
                _keep = -1;
            }

            public async Task DiscardRecv(OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                for (int i = 0; i < recvs.Length; i++)
                {
                    while (!recvs[i].Completed)
                    {
                        csp_invoke_wrap<int> recvRes = await recvs[i].TimedRecv(_keep, _lostBinBuff, 0, _lostBinBuff.Length);
                        if (recvRes.state != chan_state.ok)
                        {
                            SetCode(ExitCode.RecvBinOvertime);
                            _action.stop();
                            return;
                        }
                    }
                }
            }

            public async Task DiscardChaoticRecv(params OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                generator.lock_shield();
                generator.children children = new generator.children();
                children.ignore_suspend();
                for (int i = 0; i < recvs.Length; i++)
                {
                    int j = i;
                    children.go(async delegate ()
                    {
                        while (!recvs[j].Completed)
                        {
                            await Recv(recvs[j], _lostBinBuff, 0, _lostBinBuff.Length);
                        }
                    });
                }
                await children.wait_all();
                await generator.unlock_shield();
            }

            public OverCancel OverCancel()
            {
                assert.check(!_overCancel.get(out _), "重复的 OverCancel");
                OverCancel call = Rpc.OverCancel.Make();
                _overCancel.value = call;
                return call;
            }

            public void ClearOverSend()
            {
                _overSend.remove(out _);
            }

            private int OverSend(Func<bool, Task> action, SendName name, long count, int segment)
            {
                if (!_overSend.get(out OverSend send))
                {
                    send = new OverSend();
                    _overSend.value = send;
                }
                send.actions.AddLast(tuple.make(action, new RecvName { id = name._id, count = count, segment = segment }));
                return count >= 0 ? send.count++ : -1;
            }

            private int OverSend(Func<bool, ValueTask<csp_invoke_wrap<void_type>>> action, SendName name, long count, int segment)
            {
                return OverSend((bool cancel) => action(cancel).AsTask() ?? generator.non_async(), name, count, segment);
            }

            private ValueTask<csp_invoke_wrap<void_type>> CancelSend(SendName name)
            {
                return generator.csp_invoke(_cancelSendChan, name);
            }

            private OverSendState CheckOverSendState(int count)
            {
                if (_overSendState.get(out OverSendState sendState))
                {
                    if (!sendState.task.IsCompleted)
                    {
                        assert.check(false, "OverSend 发送异步结果未结束");
                    }
                    if (count > sendState.maxCount)
                    {
                        assert.check(false, "OverSend 发送长度溢出");
                    }
                    sendState.count += count;
                    sendState.maxCount -= count;
                }
                else
                {
                    assert.check(false, "错误的 Send");
                }
                return sendState;
            }

            public int OverSend(long count, Func<long, long, ValueTask<csp_invoke_wrap<void_type>>> sendAction)
            {
                return OverSend(count, (long offset_, long count_) => sendAction(offset_, count_).AsTask() ?? generator.non_async());
            }

            public int OverSend(long count, Func<long, long, Task> sendAction)
            {
                SendName name = new SendName { _done = count <= 0 };
                return OverSend(async delegate (bool cancel)
                {
                    if (cancel)
                    {
                        await CancelSend(name);
                        return;
                    }
                    try
                    {
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        for (long off = 0; off < count;)
                        {
                            if (0 != off)
                            {
                                generator.lock_stop();
                            }
                            sendState.count = 0;
                            sendState.maxCount = count - off;
                            await sendAction(off, count - off);
                            if (!sendState.task.IsCompleted)
                            {
                                assert.check(false, "OverSend 发送异步结果未结束");
                            }
                            chan_state state = sendState.task.Result;
                            long len = sendState.count;
                            if (len <= 0)
                            {
                                await CancelSend(name);
                                return;
                            }
                            if (state != chan_state.ok)
                            {
                                await CancelSend(name);
                                return;
                            }
                            off += len;
                            if (count != off)
                            {
                                generator.unlock_stop();
                            }
                        }
                        name._done = true;
                    }
                    catch (generator.stop_exception)
                    {
                        await CancelSend(name);
                        throw;
                    }
                }, name, count, 0);
            }

            public int OverSend(ArraySegment<byte> data, int segment = 0)
            {
                return OverTimedSend(-1, data, segment);
            }

            public int OverSend(byte[] data, int segment = 0)
            {
                return OverTimedSend(-1, data, 0, data.Length, segment);
            }

            public int OverSend(byte[] data, int offset, int count, int segment = 0)
            {
                return OverTimedSend(-1, data, offset, count, segment);
            }

            public int OverSend(IntPtr pointer, long offset, long count, int segment = 0)
            {
                return OverTimedSend(-1, pointer, offset, count, segment);
            }

            public int OverSend(SafeFileHandle file, long offset, long count, int segment = 0)
            {
                return OverTimedSend(-1, file, offset, count, segment);
            }

            public int OverTimedSend(int timed, ArraySegment<byte> data, int segment = 0)
            {
                return OverTimedSend(timed, data.Array, data.Offset, data.Count, segment);
            }

            public int OverTimedSend(int timed, byte[] data, int offset, int count, int segment = 0)
            {
                assert.check(null != data, "TimedSend data 不能为 null");
                assert.check(offset >= 0 && offset < data.Length, "TimedSend offset 越界");
                assert.check(count <= 0 || offset + count <= data.Length, "TimedSend count 越界");
                SendName name = new SendName { _done = count <= 0 };
                if (segment > 0 && segment < count)
                {
                    return OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        try
                        {
                            segment = segment <= 0 ? count : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (int off = 0; off < count; index++)
                            {
                                int len = Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend_(tuple.make(-1, timed), data, offset + off, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                    }, name, count, segment);
                }
                else
                {
                    return OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend_(tuple.make(-1, timed), data, offset, count, -1);
                    }, name, count, 0);
                }
            }

            public int OverTimedSend(int timed, IntPtr pointer, long offset, long count, int segment = 0)
            {
                assert.check(IntPtr.Zero != pointer, "OverTimedSend pointer 不能为 Zero");
                SendName name = new SendName { _done = count <= 0 };
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    return OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        try
                        {
                            segment = segment <= 0 ? (int)Math.Min(int.MaxValue, count) : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (long off = 0; off < count; index++)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend_(tuple.make(-1, timed), pointer, offset + off, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                    }, name, count, segment);
                }
                else
                {
                    return OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend_(tuple.make(-1, timed), pointer, offset, (int)count, -1);
                    }, name, count, 0);
                }
            }

            public int OverTimedSend(int timed, SafeFileHandle file, long offset, long count, int segment = 0)
            {
                assert.check(_socket is socket_tcp, "TimedSend 文件发送只能为 socket_tcp");
                SendName name = new SendName { _done = count <= 0 };
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    return OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        try
                        {
                            segment = segment <= 0 ? (int)Math.Min(int.MaxValue, count) : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (long off = 0; off < count; index++)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend_(tuple.make(-1, timed), file, offset + off, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                    }, name, count, segment);
                }
                else
                {
                    return OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend_(tuple.make(-1, timed), file, offset, (int)count, -1);
                    }, name, count, 0);
                }
            }

            public void OverHandler(Action handler)
            {
                SendName name = new SendName { _done = true };
                OverSend(delegate (bool cancel)
                {
                    if (!cancel)
                    {
                        handler();
                    }
                    return generator.non_async();
                }, name, -1, 0);
            }

            public void OverHandler(Func<Task> handler)
            {
                SendName name = new SendName { _done = true };
                OverSend(delegate (bool cancel)
                {
                    if (cancel)
                    {
                        return generator.non_async();
                    }
                    return handler();
                }, name, -1, 0);
            }

            public void CancelOverSend()
            {
                _overSend.remove();
            }

            OverCallbackList GetCallbackList(bool overStopCallback, bool waitCallbackEnd)
            {
                if (!_overCallbackList.get(out OverCallbackList callbackList))
                {
                    callbackList = new OverCallbackList();
                    callbackList.names = new LinkedList<string>();
                    _overCallbackList.value = callbackList;
                }
                if (overStopCallback && null == callbackList.stopWg)
                {
                    callbackList.stopWg = new wait_group(1, true);
                }
                if (waitCallbackEnd && null == callbackList.endWg)
                {
                    callbackList.endWg = new wait_group();
                }
                return callbackList;
            }

            public Task ClearCallback()
            {
                if (_overCallbackList.get(out OverCallbackList callbackList))
                {
                    while (0 != callbackList.names.Count)
                    {
                        Methods.Remove(callbackList.names.First.Value);
                        callbackList.names.RemoveFirst();
                    }
                    if (null != callbackList.stopWg)
                    {
                        callbackList.stopWg.force();
                        callbackList.stopWg = null;
                    }
                    if (null != callbackList.endWg)
                    {
                        wait_group endWg = callbackList.endWg;
                        callbackList.endWg = null;
                        return endWg.wait();
                    }
                }
                return generator.non_async();
            }

            public Methods.Name OverCallback(Action callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0>(Action<T0> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1>(Action<T0, T1> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2>(Action<T0, T1, T2> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3>(Action<T0, T1, T2, T3> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4>(Action<T0, T1, T2, T3, T4> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5>(Action<T0, T1, T2, T3, T4, T5> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6>(Action<T0, T1, T2, T3, T4, T5, T6> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7>(Action<T0, T1, T2, T3, T4, T5, T6, T7> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);

            public Methods.Name OverCallback<R>(Func<R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, R>(Func<T0, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, R>(Func<T0, T1, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, R>(Func<T0, T1, T2, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, R>(Func<T0, T1, T2, T3, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, R>(Func<T0, T1, T2, T3, T4, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, R>(Func<T0, T1, T2, T3, T4, T5, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, R>(Func<T0, T1, T2, T3, T4, T5, T6, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);

            public Methods.Name OverCallback(Delegate callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                OverCallbackList callbackList = GetCallbackList(overStopCallback, waitCallbackEnd);
                wait_group stopWg = overStopCallback ? callbackList.stopWg : null;
                wait_group endWg = waitCallbackEnd ? callbackList.endWg : null;
                Methods.Bind(name, callback, stopWg, endWg, runStrand ?? generator.self_strand());
                callbackList.names.AddLast(name);
                return name;
            }

            public Methods.Name OverStatic(Type type, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                OverCallbackList callbackList = GetCallbackList(overStopCallback, waitCallbackEnd);
                wait_group stopWg = overStopCallback ? callbackList.stopWg : null;
                wait_group endWg = waitCallbackEnd ? callbackList.endWg : null;
                string[] names = Methods.BindClass(name, type, null, false, stopWg, endWg, runStrand ?? generator.self_strand());
                foreach (var name_ in names)
                {
                    callbackList.names.AddLast(name_);
                }
                return name;
            }

            public Methods.Name OverObj<T>(T obj, bool declaredOnly = true, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                OverCallbackList callbackList = GetCallbackList(overStopCallback, waitCallbackEnd);
                wait_group stopWg = overStopCallback ? callbackList.stopWg : null;
                wait_group endWg = waitCallbackEnd ? callbackList.endWg : null;
                string[] names = Methods.BindClass(name, typeof(T), obj, declaredOnly, stopWg, endWg, runStrand ?? generator.self_strand());
                foreach (var name_ in names)
                {
                    callbackList.names.AddLast(name_);
                }
                return name;
            }

            private async Task<Result> Call(int timed, string name, object[] args)
            {
                long requestId = 0;
                generator sendAction = null;
                _overSend.remove(out OverSend overSend);
                _overCancel.remove(out OverCancel overCancel);
                try
                {
                    if (_rpcChan.closed)
                    {
                        return new Result { state = ReplyState.Fail };
                    }
                    if (!overCancel.Nil && overCancel.wg.is_done)
                    {
                        return new Result { state = ReplyState.LocalCancel };
                    }
                    if (null != overSend && overSend.actions.Count > 0)
                    {
                        generator.go(out sendAction, generator.self_strand(), async delegate ()
                        {
                            try
                            {
                                _session.value = this;
                                generator.lock_stop();
                                await overSend.wg.wait();
                                if (overSend.closed)
                                {
                                    overSend.actions.Clear();
                                }
                                generator.unlock_stop();
                                _overSendState.value = new OverSendState();
                                while (overSend.actions.Count > 0)
                                {
                                    generator.lock_stop();
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(false);
                                    generator.unlock_stop();
                                }
                            }
                            catch (generator.stop_exception)
                            {
                                while (overSend.actions.Count > 0)
                                {
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(true);
                                }
                                throw;
                            }
                            finally
                            {
                                _overSendState.remove();
                            }
                        });
                    }
                    requestId = Interlocked.Increment(ref _idCount);
                    csp_invoke_wrap<Result> resultWrap = await generator.csp_invoke(_rpcChan, new RpcParam { id = requestId, timed = timed, args = args, overSend = overSend, overCancel = overCancel, request = new Request { name = name, sends = overSend?.Sends() } });
                    if (chan_state.ok != resultWrap.state)
                    {
                        if (chan_state.closed == resultWrap.state)
                        {
                            requestId = 0;
                            overSend?.Close();
                        }
                        return new Result { state = ReplyState.Fail };
                    }
                    switch (resultWrap.result.state)
                    {
                        case ReplyState.Overtime:
                        case ReplyState.LocalCancel:
                            return resultWrap.result;
                        default:
                            if (null != sendAction && !sendAction.is_completed() && 0 == timed && ReplyState.Success == resultWrap.result.state)
                            {
                                overCancel.wg?.async_wait(() => sendAction.stop());
                                await generator.wait_other(sendAction);
                                if (sendAction.is_force())
                                {
                                    resultWrap.result.state = ReplyState.LocalCancel;
                                }
                            }
                            requestId = 0;
                            return resultWrap.result;
                    }
                }
                catch (generator.stop_exception)
                {
                    if (null != sendAction)
                    {
                        if (_rpcChan.closed)
                        {
                            requestId = 0;
                            overSend.Close();
                        }
                        else if (!_rpcChan.strand.running_in_this_thread())
                        {
                            _rpcChan.strand.post(delegate ()
                            {
                                if (_rpcChan.closed)
                                {
                                    overSend.Close();
                                }
                            });
                        }
                    }
                    throw;
                }
                finally
                {
                    generator.lock_shield();
                    if (null != sendAction && !sendAction.is_completed())
                    {
                        await generator.stop_other(sendAction);
                    }
                    if (0 != requestId)
                    {
                        _cancelRpcChan.post(requestId);
                    }
                    await ClearCallback();
                    await generator.unlock_shield();
                }
            }

            public Task<Result> Call(int timed, string name) => Call(timed, name, new object[] { });
            public Task<Result> Call(int timed, string name, object p0) => Call(timed, name, new object[] { p0 });
            public Task<Result> Call(int timed, string name, object p0, object p1) => Call(timed, name, new object[] { p0, p1 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2) => Call(timed, name, new object[] { p0, p1, p2 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3) => Call(timed, name, new object[] { p0, p1, p2, p3 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4) => Call(timed, name, new object[] { p0, p1, p2, p3, p4 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe });
            public Task<Result> Call(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => Call(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf });

            private Task<Result> Call(string name, object[] args) => Call(-1, name, args);

            public Task<Result> Call(string name) => Call(name, new object[] { });
            public Task<Result> Call(string name, object p0) => Call(name, new object[] { p0 });
            public Task<Result> Call(string name, object p0, object p1) => Call(name, new object[] { p0, p1 });
            public Task<Result> Call(string name, object p0, object p1, object p2) => Call(name, new object[] { p0, p1, p2 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3) => Call(name, new object[] { p0, p1, p2, p3 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4) => Call(name, new object[] { p0, p1, p2, p3, p4 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5) => Call(name, new object[] { p0, p1, p2, p3, p4, p5 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe });
            public Task<Result> Call(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => Call(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf });

            private async Task<Result<R>> Call<R>(int timed, string name, object[] args)
            {
                Result result = await Call(timed, name, args);
                if (result.state != ReplyState.Success)
                {
                    return new Result<R> { state = result.state, message = result.message };
                }
                try
                {
                    return new Result<R> { state = result.state, result = ParamTuple.DeserializeCheck<R>(result.result) };
                }
                catch (Exception)
                {
                    return new Result<R> { state = ReplyState.ResultTypeError };
                }
            }

            public Task<Result<R>> Call<R>(int timed, string name) => Call<R>(timed, name, new object[] { });
            public Task<Result<R>> Call<R>(int timed, string name, object p0) => Call<R>(timed, name, new object[] { p0 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1) => Call<R>(timed, name, new object[] { p0, p1 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2) => Call<R>(timed, name, new object[] { p0, p1, p2 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3) => Call<R>(timed, name, new object[] { p0, p1, p2, p3 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe });
            public Task<Result<R>> Call<R>(int timed, string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => Call<R>(timed, name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf });

            private Task<Result<R>> Call<R>(string name, object[] args) => Call<R>(-1, name, args);

            public Task<Result<R>> Call<R>(string name) => Call<R>(name, new object[] { });
            public Task<Result<R>> Call<R>(string name, object p0) => Call<R>(name, new object[] { p0 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1) => Call<R>(name, new object[] { p0, p1 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2) => Call<R>(name, new object[] { p0, p1, p2 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3) => Call<R>(name, new object[] { p0, p1, p2, p3 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4) => Call<R>(name, new object[] { p0, p1, p2, p3, p4 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe });
            public Task<Result<R>> Call<R>(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => Call<R>(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf });

            private Task<Result> Post(string name, object[] args) => Call(0, name, args);

            public Task<Result> Post(string name) => Post(name, new object[] { });
            public Task<Result> Post(string name, object p0) => Post(name, new object[] { p0 });
            public Task<Result> Post(string name, object p0, object p1) => Post(name, new object[] { p0, p1 });
            public Task<Result> Post(string name, object p0, object p1, object p2) => Post(name, new object[] { p0, p1, p2 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3) => Post(name, new object[] { p0, p1, p2, p3 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4) => Post(name, new object[] { p0, p1, p2, p3, p4 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5) => Post(name, new object[] { p0, p1, p2, p3, p4, p5 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe });
            public Task<Result> Post(string name, object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => Post(name, new object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf });

            public void RemoteClose()
            {
                _remoteCmdChan.post(DataType.Close);
            }

            public void NoKeep()
            {
                _remoteCmdChan.post(DataType.NoKeep);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(ArraySegment<byte> data, int index = -1)
            {
                return TimedSend(tuple.make(-1, -1), data.Array, data.Offset, data.Count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(byte[] data, int index = -1)
            {
                return TimedSend(tuple.make(-1, -1), data, 0, data.Length, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(byte[] data, int offset, int count, int index = -1)
            {
                return TimedSend(tuple.make(-1, -1), data, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(IntPtr pointer, long offset, int count, int index = -1)
            {
                return TimedSend(tuple.make(-1, -1), pointer, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(SafeFileHandle file, long offset, int count, int index = -1)
            {
                return TimedSend(tuple.make(-1, -1), file, offset, count, index);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, ArraySegment<byte> buff)
            {
                return TimedRecv(name, tuple.make(-1, -1), buff.Array, buff.Offset, buff.Count);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, byte[] buff)
            {
                return TimedRecv(name, tuple.make(-1, -1), buff, 0, buff.Length);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, byte[] buff, int offset, int count)
            {
                return TimedRecv(name, tuple.make(-1, -1), buff, offset, count);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, IntPtr pointer, long offset, int count)
            {
                return TimedRecv(name, tuple.make(-1, -1), pointer, offset, count);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, ArraySegment<byte> data, int index = -1)
            {
                return TimedSend(tuple.make(timed, -1), data.Array, data.Offset, data.Count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, byte[] data, int index = -1)
            {
                return TimedSend(tuple.make(timed, -1), data, 0, data.Length, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, byte[] data, int offset, int count, int index = -1)
            {
                return TimedSend(tuple.make(timed, -1), data, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, IntPtr pointer, long offset, int count, int index = -1)
            {
                return TimedSend(tuple.make(timed, -1), pointer, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, SafeFileHandle file, long offset, int count, int index = -1)
            {
                return TimedSend(tuple.make(timed, -1), file, offset, count, index);
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, ArraySegment<byte> buff)
            {
                return TimedRecv(name, timed, buff.Array, buff.Offset, buff.Count);
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, byte[] buff)
            {
                return TimedRecv(name, tuple.make(timed, -1), buff, 0, buff.Length);
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, byte[] buff, int offset, int count)
            {
                return TimedRecv(name, tuple.make(timed, -1), buff, offset, count);
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, IntPtr pointer, long offset, int count)
            {
                return TimedRecv(name, tuple.make(timed, -1), pointer, offset, count);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, ArraySegment<byte> data, int index = -1)
            {
                return TimedSend(timed, data.Array, data.Offset, data.Count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, byte[] data, int index = -1)
            {
                return TimedSend(timed, data, 0, data.Length, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, byte[] data, int offset, int count, int index = -1)
            {
                if (!_session.get(out Session this_))
                {
                    assert.check(false, "错误的 Send");
                }
                return this_.TimedSend_(timed, data, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, IntPtr pointer, long offset, int count, int index = -1)
            {
                if (!_session.get(out Session this_))
                {
                    assert.check(false, "错误的 Send");
                }
                return this_.TimedSend_(timed, pointer, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, SafeFileHandle file, long offset, int count, int index = -1)
            {
                if (!_session.get(out Session this_))
                {
                    assert.check(false, "错误的 Send");
                }
                return this_.TimedSend_(timed, file, offset, count, index);
            }

            private ValueTask<csp_invoke_wrap<void_type>> TimedSend_(tuple<int, int> timed, byte[] data, int offset, int count, int index)
            {
                assert.check(null != data, "TimedSend data 不能为 null");
                assert.check(offset >= 0 && offset < data.Length, "TimedSend offset 越界");
                assert.check(count > 0 && offset + count <= data.Length, "TimedSend count 越界");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed.value1, new SendByteParam { name = sendState.name, timed = timed.value2, index = index, data = data, offset = offset, count = count });
            }

            private ValueTask<csp_invoke_wrap<void_type>> TimedSend_(tuple<int, int> timed, IntPtr pointer, long offset, int count, int index)
            {
                assert.check(IntPtr.Zero != pointer, "TimedSend pointer 不能为 Zero");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendPtrChan, timed.value1, new SendPtrParam { name = sendState.name, timed = timed.value2, index = index, pointer = pointer, offset = offset, count = count });
            }

            private ValueTask<csp_invoke_wrap<void_type>> TimedSend_(tuple<int, int> timed, SafeFileHandle file, long offset, int count, int index)
            {
                assert.check(_socket is socket_tcp, "TimedSend 文件发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendFileChan, timed.value1, new SendFileParam { name = sendState.name, timed = timed.value2, index = index, file = file, offset = offset, count = count });
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, tuple<int, int> timed, ArraySegment<byte> buff)
            {
                return TimedRecv(name, timed, buff.Array, buff.Offset, buff.Count);
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, tuple<int, int> timed, byte[] buff)
            {
                return TimedRecv(name, timed, buff, 0, buff.Length);
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, tuple<int, int> timed, byte[] buff, int offset, int count)
            {
                assert.check(name._session == this, "OverRecv 不属于当前 Session");
                assert.check(null != buff, "TimedRecv buff 不能为 null");
                assert.check(offset >= 0 && offset < buff.Length, "TimedRecv offset 越界");
                assert.check(count > 0 && offset + count <= buff.Length, "TimedRecv count 越界");
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    assert.check(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (name.Full)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                chan_state state = await generator.chan_send(_namedRecvChan, name);
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(name._csp, timed.value1, new RecvParam { timed = timed.value2, buff = buff, offset = offset, count = count });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, tuple<int, int> timed, IntPtr pointer, long offset, int count)
            {
                assert.check(name._session == this, "OverRecv 不属于当前 Session");
                assert.check(IntPtr.Zero != pointer, "TimedRecv pointer 不能为 Zero");
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    assert.check(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (name.Full)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                chan_state state = await generator.chan_send(_namedRecvChan, name);
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(name._csp, timed.value1, new RecvParam { timed = timed.value2, pointer = pointer, offset = offset, count = count });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            struct ReplyMapValue
            {
                public async_timer timer;
                public csp_result<Result> result;
            }

            struct SendRequestParam
            {
                public long id;
                public object[] args;
                public Request request;
                public OverSend overSend;
            }

            struct RecvRequestParam
            {
                public long id;
                public bool cancel;
                public object[] args;
                public string[] fields;
                public Request request;
            }

            struct RecvReplyParam
            {
                public long id;
                public ReplyState state;
                public object result;
                public Reply reply;
            }

            struct SendReplyParam
            {
                public long id;
                public object result;
                public Reply reply;
            }

            struct SendBuffParam
            {
                public int count;
                public OverSend overSend;
            }

            private void SetCode(ExitCode code)
            {
                Interlocked.CompareExchange(ref _exitCode, (int)code, (int)ExitCode.Undefined);
            }

            private async Task Run()
            {
                generator.children ioChild = new generator.children();
                chan_lost_msg<csp_wait_wrap<Result, RpcParam>> rpcLost = new chan_lost_msg<csp_wait_wrap<Result, RpcParam>>();
                Dictionary<long, ReplyMapValue> replyDict = new Dictionary<long, ReplyMapValue>();
                chan<SendRequestParam> sendRequestChan = chan<SendRequestParam>.make(-1);
                try
                {
                    int keep = _keep;
                    if (keep <= 0)
                    {
                        NoKeep();
                    }
                    bool isTcp = _socket is socket_tcp;
                    bool sendBin = false, recvBin = false;
                    async_timer recvTimer = new async_timer();
                    async_timer sendTimer = new async_timer();
                    chan<RecvRequestParam> recvRequestChan = chan<RecvRequestParam>.make(-1);
                    chan<RecvReplyParam> recvReplyChan = chan<RecvReplyParam>.make(-1);
                    chan<SendReplyParam> sendReplyChan = chan<SendReplyParam>.make(-1);
                    ioChild.go(async delegate ()
                    {
                        byte[] recvHead = new byte[17];
                        byte[] recvBuff1 = new byte[1024 * 1024];
                        byte[] recvBuff2 = new byte[1024 * 1024];
                        BinaryFormatter deserializer = new BinaryFormatter();
                        Map<long, OverRecv> namedMap = new Map<long, OverRecv>(true);
                        chan_lost_msg<OverRecv> namedLost = new chan_lost_msg<OverRecv>();
                        try
                        {
                            DataType lastType = DataType.Keep;
                            Action timerKeepHandler = delegate ()
                            {
                                switch (lastType)
                                {
                                    case DataType.Bin:
                                    case DataType.BinCancel:
                                        SetCode(ExitCode.RecvKeepOvertime);
                                        break;
                                    default:
                                        SetCode(ExitCode.KeepOvertime);
                                        break;
                                }
                                _action.stop();
                            };
                            Action timerRecvHandler = delegate ()
                            {
                                SetCode(ExitCode.RecvBinOvertime);
                                _action.stop();
                            };
                            if (keep > 0)
                            {
                                recvTimer.timeout(keep, timerKeepHandler);
                            }
                            Task deserializeTask = generator.non_async();
                            while (true)
                            {
                                if (!await _socket.read(recvHead))
                                {
                                    goto socketClosed;
                                }
                                recvTimer.restart();
                                ReadHead(recvHead, out long id, out int len1, out int len2, out DataType type);
                                lastType = type;
                                switch (type)
                                {
                                    case DataType.Keep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        break;
                                    case DataType.NoKeep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        keep = -1;
                                        recvTimer.cancel();
                                        if (!sendBin)
                                        {
                                            sendTimer.cancel();
                                        }
                                        break;
                                    case DataType.RequestCancel:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        recvRequestChan.post(new RecvRequestParam { id = id, cancel = true });
                                        break;
                                    case DataType.Request:
                                    case DataType.Reply:
                                        if (len1 <= 0 || len2 < 0 || len1 + len2 > recvBuff1.Length)
                                        {
                                            goto dataHeadError;
                                        }
                                        if (!await _socket.read(new ArraySegment<byte>(recvBuff1, 0, len1 + len2)))
                                        {
                                            goto socketClosed;
                                        }
                                        await generator.wait_task(deserializeTask);
                                        Swap(ref recvBuff1, ref recvBuff2);
                                        (deserializeTask = new Task(delegate ()
                                        {
                                            MemoryStream stream = new MemoryStream(recvBuff2, 0, len1 + len2);
                                            switch (type)
                                            {
                                                case DataType.Request:
                                                    try
                                                    {
                                                        Request request = (Request)deserializer.Deserialize(stream);
                                                        try
                                                        {
                                                            string[] fields = null;
                                                            if (request.name[request.name.Length - 1] == ']')
                                                            {
                                                                fields = request.name.Split('.');
                                                                request.name = fields[0];
                                                            }
                                                            else
                                                            {
                                                                bool lastDot = false;
                                                                for (int i = 0; i < request.name.Length; i++)
                                                                {
                                                                    if (request.name[i] != '.')
                                                                    {
                                                                        continue;
                                                                    }
                                                                    if (lastDot)
                                                                    {
                                                                        fields = request.name.Split('.');
                                                                        request.name = fields[0];
                                                                        break;
                                                                    }
                                                                    lastDot = true;
                                                                }
                                                            }
                                                            object[] args = 0 != len2 ? (object[])deserializer.Deserialize(stream) : null;
                                                            recvRequestChan.post(new RecvRequestParam { id = id, cancel = false, args = args, fields = fields, request = request });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            sendReplyChan.post(new SendReplyParam { id = id, reply = new Reply { state = ReplyState.RemoteDeserializeError } });
                                                            if (null != request.sends)
                                                            {
                                                                recvRequestChan.post(new RecvRequestParam { id = id, cancel = true, request = request });
                                                            }
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        SetCode(ExitCode.RequestDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                                case DataType.Reply:
                                                    try
                                                    {
                                                        Reply reply = (Reply)deserializer.Deserialize(stream);
                                                        try
                                                        {
                                                            object result = (0 != len2 && reply.state == ReplyState.Success) ? deserializer.Deserialize(stream) : null;
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, result = result, reply = reply });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalDeserializeError } });
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        SetCode(ExitCode.ReplyDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                            }
                                        })).Start();
                                        break;
                                    case DataType.Bin:
                                        if (len2 <= 0)
                                        {
                                            goto dataHeadError;
                                        }
                                        {
                                            int position = 0;
                                            bool lastFind = true;
                                            while (position != len2)
                                            {
                                                var tempNode = lastFind ? namedMap.FindFirst(id) : null;
                                                if (!(lastFind = null != tempNode))
                                                {
                                                    do
                                                    {
                                                        chan_recv_wrap<OverRecv> namedCsp = await _namedRecvChan.receive(namedLost);
                                                        tempNode = namedMap.Insert(namedCsp.msg._id, namedCsp.msg);
                                                    } while (tempNode.Key != id);
                                                }
                                                tempNode.Value._index = len1;
                                                csp_wait_wrap<int, RecvParam> cspParam = await tempNode.Value._csp.wait();
                                                if (cspParam.state != chan_state.ok)
                                                {
                                                    goto socketClosed;
                                                }
                                                int count = cspParam.msg.count;
                                                if (count > len2 - position)
                                                {
                                                    count = len2 - position;
                                                }
                                                if (count <= 0)
                                                {
                                                    recvTimer.restart();
                                                    cspParam.complete(0);
                                                }
                                                else
                                                {
                                                    recvBin = true;
                                                    recvTimer.cancel();
                                                    if (cspParam.msg.timed >= 0)
                                                    {
                                                        recvTimer.timeout(cspParam.msg.timed, timerRecvHandler);
                                                    }
                                                    socket_result result;
                                                    generator.lock_stop();
                                                    if (IntPtr.Zero == cspParam.msg.pointer)
                                                    {
                                                        result = await _socket.read(new ArraySegment<byte>(cspParam.msg.buff, (int)cspParam.msg.offset, count));
                                                    }
                                                    else if (isTcp)
                                                    {
                                                        result = await ((socket_tcp)_socket).read(cspParam.msg.pointer, cspParam.msg.offset, count);
                                                    }
                                                    else
                                                    {
                                                        result = await ((socket_pipe)_socket).read(cspParam.msg.pointer, cspParam.msg.offset, count);
                                                    }
                                                    generator.unlock_stop();
                                                    if (!result)
                                                    {
                                                        cspParam.complete(-1);
                                                        goto socketClosed;
                                                    }
                                                    position += result.size;
                                                    recvBin = false;
                                                    if (cspParam.msg.timed >= 0)
                                                    {
                                                        recvTimer.cancel();
                                                    }
                                                    if (keep > 0)
                                                    {
                                                        recvTimer.timeout(keep, timerKeepHandler);
                                                    }
                                                    cspParam.complete(result.size);
                                                }
                                                namedMap.Remove(tempNode);
                                            }
                                        }
                                        break;
                                    case DataType.BinCancel:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        {
                                            var tempNode = namedMap.FindFirst(id);
                                            if (null == tempNode)
                                            {
                                                do
                                                {
                                                    chan_recv_wrap<OverRecv> namedCsp = await _namedRecvChan.receive(namedLost);
                                                    tempNode = namedMap.Insert(namedCsp.msg._id, namedCsp.msg);
                                                } while (tempNode.Key != id);
                                            }
                                            (await tempNode.Value._csp.wait()).complete(-2);
                                            namedMap.Remove(tempNode);
                                        }
                                        break;
                                    case DataType.Close:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        SetCode(ExitCode.RemoteClose);
                                        return;
                                    default:
                                        goto dataHeadError;
                                }
                            }
dataHeadError:
                            SetCode(ExitCode.DataHeadError);
                            return;
socketClosed:
                            SetCode(ExitCode.SocketClosed);
                            return;
                        }
                        finally
                        {
                            generator.lock_stop();
                            recvTimer.cancel();
                            _action.stop();
                            _namedRecvChan.close();
                            if (namedLost.has)
                            {
                                namedLost.msg._csp.close();
                                namedLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await _namedRecvChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg._csp.close();
                            }
                            foreach (var item in namedMap)
                            {
                                item.value2._csp.close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        byte[] sendHead = new byte[17];
                        byte[] sendBuff1 = new byte[sendHead.Length + 1024 * 1024];
                        byte[] sendBuff2 = new byte[sendHead.Length + 1024 * 1024];
                        wait_group sendBuffWg = new wait_group();
                        chan_lost_msg<SendBuffParam> sendBuffLost = new chan_lost_msg<SendBuffParam>();
                        chan_lost_msg<SendRequestParam> sendRequestLost = new chan_lost_msg<SendRequestParam>();
                        chan<SendBuffParam> sendBuffChan = chan<SendBuffParam>.make(1);
                        generator.children serializerChild = new generator.children();
                        serializerChild.go(async delegate ()
                        {
                            BinaryFormatter serializer = new BinaryFormatter();
                            try
                            {
                                await generator.select().case_receive(sendReplyChan, async delegate (SendReplyParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            MemoryStream sendStream = new MemoryStream(sendBuff1, sendHead.Length, sendBuff1.Length - sendHead.Length);
                                            serializer.Serialize(sendStream, param.reply);
                                            len1 = (int)sendStream.Position;
                                            if (null != param.result)
                                            {
                                                try
                                                {
                                                    param.result = ParamTuple.SerializeCheck(param.result);
                                                    serializer.Serialize(sendStream, param.result);
                                                    len2 = (int)sendStream.Position - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    sendStream.Position = 0;
                                                    serializer.Serialize(sendStream, new Reply { state = ReplyState.RemoteSerializeError });
                                                    len1 = (int)sendStream.Position;
                                                }
                                            }
                                        }
                                        catch (Exception)
                                        {
                                            SetCode(ExitCode.ReplySerializeError);
                                            throw;
                                        }
                                    });
                                    WriteHead(sendBuff1, param.id, len1, len2, DataType.Reply);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref sendBuff1, ref sendBuff2);
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2 });
                                }).case_receive(sendRequestChan, async delegate (SendRequestParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    sendRequestLost.set(param);
                                    if (!await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            MemoryStream sendStream = new MemoryStream(sendBuff1, sendHead.Length, sendBuff1.Length - sendHead.Length);
                                            serializer.Serialize(sendStream, param.request);
                                            len1 = (int)sendStream.Position;
                                            if (null != param.args)
                                            {
                                                try
                                                {
                                                    for (int i = 0; i < param.args.Length; i++)
                                                    {
                                                        param.args[i] = ParamTuple.SerializeCheck(param.args[i]);
                                                    }
                                                    serializer.Serialize(sendStream, param.args);
                                                    len2 = (int)sendStream.Position - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    recvReplyChan.post(new RecvReplyParam { id = param.id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalSerializeError } });
                                                    return false;
                                                }
                                            }
                                            return true;
                                        }
                                        catch (Exception)
                                        {
                                            SetCode(ExitCode.RequestSerializeError);
                                            throw;
                                        }
                                    }))
                                    {
                                        param.overSend?.Close();
                                        sendRequestLost.clear();
                                        return;
                                    }
                                    WriteHead(sendBuff1, param.id, len1, len2, DataType.Request);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref sendBuff1, ref sendBuff2);
                                    sendRequestLost.clear();
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2, overSend = param.overSend });
                                }, lostMsg: sendRequestLost).loop();
                            }
                            catch (generator.stop_exception) { throw; }
                            catch (Exception) { }
                            finally
                            {
                                generator.lock_stop();
                                _action.stop();
                                if (sendRequestLost.has)
                                {
                                    sendRequestLost.msg.overSend?.Close();
                                    sendRequestLost.clear();
                                }
                                generator.unlock_stop();
                            }
                        });
                        try
                        {
                            chan<void_type> keepChan = chan<void_type>.make(1);
                            Action timerKeepHandler = keepChan.wrap_try_default();
                            Action timerSendHandler = delegate ()
                            {
                                SetCode(ExitCode.SendBinOvertime);
                                _action.stop();
                            };
                            if (keep > 0)
                            {
                                sendTimer.interval(keep / 2, timerKeepHandler);
                            }
                            await generator.select().case_receive(_remoteCmdChan, async delegate (DataType cmd)
                            {
                                WriteHead(sendHead, 0L, 0, 0, cmd);
                                switch (cmd)
                                {
                                    case DataType.NoKeep:
                                        keep = -1;
                                        sendTimer.cancel();
                                        if (!recvBin)
                                        {
                                            recvTimer.cancel();
                                        }
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                            return;
                                        }
                                        break;
                                    case DataType.Close:
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                            return;
                                        }
                                        SetCode(ExitCode.LocalClose);
                                        _remoteCmdChan.close();
                                        WriteHead(sendHead, 0L, 0, 0, DataType.Keep);
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                            return;
                                        }
                                        await generator.hold();
                                        break;
                                }
                            }).case_receive(_cancelRpcChan, async delegate (long id)
                            {
                                WriteHead(sendHead, id, 0, 0, DataType.RequestCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                            }).case_receive(sendBuffChan, async delegate (SendBuffParam param)
                            {
                                param.overSend?.wg.force();
                                if (!await _socket.write(new ArraySegment<byte>(sendBuff2, 0, param.count)))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBuffWg.done();
                            }, lostMsg: sendBuffLost).case_receive(_cancelSendChan, async delegate (SendName name)
                            {
                                if (name._done)
                                {
                                    return;
                                }
                                name._done = true;
                                WriteHead(sendHead, name._id, 0, 0, DataType.BinCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                            }).case_receive(_sendByteChan, async delegate (SendByteParam param)
                            {
                                if (param.name._done)
                                {
                                    return;
                                }
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                WriteHead(sendHead, param.name._id, param.index, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = true;
                                sendTimer.cancel();
                                if (param.timed >= 0)
                                {
                                    sendTimer.timeout(param.timed, timerSendHandler);
                                }
                                generator.lock_stop();
                                socket_result result = await _socket.write(new ArraySegment<byte>(param.data, param.offset, param.count));
                                generator.unlock_stop();
                                if (!result)
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = false;
                                if (param.timed >= 0)
                                {
                                    sendTimer.cancel();
                                }
                                if (keep > 0)
                                {
                                    sendTimer.interval(keep / 2, timerKeepHandler);
                                }
                            }).case_receive(_sendPtrChan, async delegate (SendPtrParam param)
                            {
                                if (param.name._done)
                                {
                                    return;
                                }
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                WriteHead(sendHead, param.name._id, param.index, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = true;
                                sendTimer.cancel();
                                if (param.timed >= 0)
                                {
                                    sendTimer.timeout(param.timed, timerSendHandler);
                                }
                                socket_result result;
                                generator.lock_stop();
                                if (isTcp)
                                {
                                    result = await ((socket_tcp)_socket).write(param.pointer, param.offset, param.count);
                                }
                                else
                                {
                                    result = await ((socket_pipe)_socket).write(param.pointer, param.offset, param.count);
                                }
                                generator.unlock_stop();
                                if (!result)
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = false;
                                if (param.timed >= 0)
                                {
                                    sendTimer.cancel();
                                }
                                if (keep > 0)
                                {
                                    sendTimer.interval(keep / 2, timerKeepHandler);
                                }
                            }).case_receive(_sendFileChan, async delegate (SendFileParam param)
                            {
                                if (param.name._done)
                                {
                                    return;
                                }
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                if (!isTcp)
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                WriteHead(sendHead, param.name._id, param.index, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = true;
                                sendTimer.cancel();
                                if (param.timed >= 0)
                                {
                                    sendTimer.timeout(param.timed, timerSendHandler);
                                }
                                generator.lock_stop();
                                socket_result result = await ((socket_tcp)_socket).send_file(param.file, param.offset, param.count);
                                generator.unlock_stop();
                                if (!result)
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = false;
                                if (param.timed >= 0)
                                {
                                    sendTimer.cancel();
                                }
                                if (keep > 0)
                                {
                                    sendTimer.interval(keep / 2, timerKeepHandler);
                                }
                            }).case_receive(keepChan, async delegate ()
                            {
                                WriteHead(sendHead, 0L, 0, 0, DataType.Keep);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                            }).loop();
                            SetCode(ExitCode.SocketClosed);
                        }
                        finally
                        {
                            generator.lock_stop();
                            await serializerChild.stop();
                            sendTimer.cancel();
                            _action.stop();
                            _sendPtrChan.close();
                            _sendByteChan.close();
                            _sendFileChan.close();
                            _cancelRpcChan.close();
                            _cancelSendChan.close();
                            _remoteCmdChan.close();
                            sendBuffChan.close();
                            if (sendBuffLost.has)
                            {
                                sendBuffLost.msg.overSend?.Close();
                                sendBuffLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await sendBuffChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg.overSend?.Close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        mt19937 mt = new mt19937();
                        generator.children callChild = new generator.children();
                        ConcurrentDictionary<long, RpcCancel> rpcCancelDict = new ConcurrentDictionary<long, RpcCancel>();
                        while (true)
                        {
                            RecvRequestParam request = await recvRequestChan.receive();
                            OverRecv[] recvs = null;
                            if (null != request.request.sends)
                            {
                                recvs = new OverRecv[request.request.sends.Length];
                                for (int i = 0; i < request.request.sends.Length; i++)
                                {
                                    if (!request.request.sends[i].Check())
                                    {
                                        SetCode(ExitCode.RecvBinError);
                                        _action.stop();
                                        return;
                                    }
                                    recvs[i] = new OverRecv(request.request.sends[i], this, new csp_chan<int, RecvParam>(_strands[0]));
                                }
                            }
                            if (request.cancel)
                            {
                                if (rpcCancelDict.TryRemove(request.id, out RpcCancel rpcCancel))
                                {
                                    rpcCancel.wg.force();
                                }
                                if (null != recvs)
                                {
                                    callChild.free_go(_strands[0], () => DiscardRecv(recvs));
                                }
                                continue;
                            }
                            tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand> handler;
                            if (null == request.request.name || null == request.args || !_methods.Get(request.request.name, out handler))
                            {
                                sendReplyChan.post(new SendReplyParam { id = request.id, reply = new Reply { state = ReplyState.NotFound } });
                                if (null != recvs)
                                {
                                    callChild.free_go(_strands[0], () => DiscardRecv(recvs));
                                }
                            }
                            else
                            {
                                RpcCancel rpcCancel = new RpcCancel { wg = new wait_group(1, true) };
                                if (!rpcCancelDict.TryAdd(request.id, rpcCancel))
                                {
                                    sendReplyChan.post(new SendReplyParam { id = request.id, reply = new Reply { state = ReplyState.NotFound } });
                                    continue;
                                }
                                callChild.free_go(handler.value2 ?? _strands[1 == _strands.Length ? 0 : (1 + (int)((_strands.Length - 1) * mt.NextDouble()))], async delegate ()
                                {
                                    object result = null;
                                    Reply reply = new Reply();
                                    try
                                    {
                                        _session.value = this;
                                        _rpcCancel.value = rpcCancel;
                                        _recvList.value = new RecvList { recvs = recvs };
                                        async_result_wrap<object, ReplyState> resultWrap = new async_result_wrap<object, ReplyState>
                                        {
                                            value1 = request.fields,
                                            value2 = ReplyState.Success
                                        };
                                        await handler.value1(resultWrap, request.args);
                                        if ((reply.state = resultWrap.value2) == ReplyState.Success)
                                        {
                                            result = resultWrap.value1;
                                        }
                                    }
                                    catch (generator.stop_exception)
                                    {
                                        reply.state = ReplyState.Stopped;
                                        throw;
                                    }
                                    catch (CancelException)
                                    {
                                        reply.state = ReplyState.RemoteCancel;
                                    }
                                    catch (CastArgsException ec)
                                    {
                                        reply.state = ec.state;
                                    }
                                    catch (Exception ec)
                                    {
                                        reply.state = ReplyState.Exception;
                                        if (null != ec.InnerException)
                                        {
                                            Exception inner = ec.InnerException;
                                            reply.message = $"{inner.Message}\r\n{ec.Message}\r\n{inner.Source}\r\n{ec.Source}\r\n{inner.StackTrace}\r\n{ec.StackTrace}";
                                        }
                                        else
                                        {
                                            reply.message = $"{ec.Message}\r\n{ec.Source}\r\n{ec.StackTrace}";
                                        }
                                    }
                                    finally
                                    {
                                        generator.lock_stop();
                                        await ClearCallback();
                                        if (rpcCancelDict.TryRemove(request.id, out var _) && request.request.reply)
                                        {
                                            sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                        }
                                        generator.children[] children = generator.all_children();
                                        if (children.Length > 0)
                                        {
                                            await generator.children.stop(children);
                                        }
                                        if (null != recvs)
                                        {
                                            for (int i = 0; i < recvs.Length && (int)ExitCode.Undefined == _exitCode; i++)
                                            {
                                                while (!recvs[i].Completed)
                                                {
                                                    csp_invoke_wrap<int> recvRes = await recvs[i].TimedRecv(_keep, _lostBinBuff, 0, _lostBinBuff.Length);
                                                    if (recvRes.state != chan_state.ok)
                                                    {
                                                        SetCode(ExitCode.RecvBinOvertime);
                                                        _action.stop();
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        generator.unlock_stop();
                                    }
                                });
                            }
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        while (true)
                        {
                            RecvReplyParam reply = await recvReplyChan.receive();
                            if (replyDict.TryGetValue(reply.id, out var replyPack))
                            {
                                replyDict.Remove(reply.id);
                                replyPack.timer?.cancel();
                                if (reply.state == ReplyState.Success)
                                {
                                    replyPack.result.complete(new Result { state = reply.reply.state, result = reply.result, message = reply.reply.message });
                                }
                                else
                                {
                                    replyPack.result.complete(new Result { state = reply.state });
                                }
                            }
                        }
                    });
                    while (true)
                    {
                        var rpc = await _rpcChan.wait(rpcLost);
                        if (rpc.state != chan_state.ok)
                        {
                            break;
                        }
                        long id = rpc.msg.id;
                        if (rpc.msg.timed > 0)
                        {
                            rpc.msg.request.reply = true;
                            async_timer timer = new async_timer();
                            replyDict.Add(id, new ReplyMapValue { timer = timer, result = rpc.result });
                            timer.timeout(rpc.msg.timed, () => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Overtime }));
                        }
                        else if (rpc.msg.timed < 0)
                        {
                            rpc.msg.request.reply = true;
                            replyDict.Add(id, new ReplyMapValue { result = rpc.result });
                        }
                        else
                        {
                            rpc.msg.request.reply = false;
                            rpc.complete(new Result { state = ReplyState.Success });
                        }
                        if (rpc.msg.request.reply)
                        {
                            rpc.msg.overCancel.wg?.async_wait(() => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.LocalCancel }));
                        }
                        sendRequestChan.post(new SendRequestParam { id = id, args = rpc.msg.args, request = rpc.msg.request, overSend = rpc.msg.overSend });
                    }
                }
                finally
                {
                    generator.lock_stop();
                    _socket.close();
                    await ioChild.stop();
                    _rpcChan.close();
                    sendRequestChan.close();
                    if (rpcLost.has)
                    {
                        rpcLost.msg.msg.overSend?.Close();
                        rpcLost.msg.fail();
                        rpcLost.clear();
                    }
                    foreach (var item in replyDict)
                    {
                        item.Value.timer?.cancel();
                        item.Value.result.fail();
                    }
                    while (true)
                    {
                        var wrap = await _rpcChan.wait();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                        wrap.fail();
                    }
                    while (true)
                    {
                        var wrap = await sendRequestChan.receive();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                    }
                    generator.unlock_stop();
                }
            }
        }
    }
}
